Skip to content

Commit

Permalink
Google Help: Improve the link target (#2536)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaVinci9196 authored Sep 28, 2024
1 parent 112cd65 commit 09cf3c8
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 18 deletions.
53 changes: 53 additions & 0 deletions play-services-core-proto/src/main/proto/help.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

option java_package = "org.microg.gms.googlehelp";

option java_multiple_files = true;

message RequestContent {
optional CallerAppInfo appInfo = 1;
optional DeviceInfo deviceInfo = 2;
optional RequestBody body = 3;
optional string host = 4;
}

message ResponseContentWarp {
optional ResponseContent content = 1;
}

message ResponseContent {
optional AnswerInfo info = 1;
optional uint32 theme = 2;
}

message AnswerInfo {
optional string answerId = 1;
optional string answerTitle = 2;
optional string answerUrl = 3;
optional uint32 type = 5;
}

message CallerAppInfo {
optional string packageName = 1;
optional string version = 2;
}

message DeviceInfo {
optional string language = 1;
optional string name = 2;
optional string version = 3;
optional string code = 7;
optional string timeZone = 9;
}

message RequestBody {
optional string appContext = 3;
optional string session = 4;
optional uint32 gmsVersionCode = 12;
optional string gmsVersionName = 13;
optional uint32 type = 26;
optional string ap = 28;
}
4 changes: 2 additions & 2 deletions play-services-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@
<!-- microG Settings activity -->
<activity
android:name="org.microg.gms.ui.MainSettingsActivity"
android:exported="true"
android:icon="@mipmap/ic_app_settings"
android:label="@string/gms_settings_name"
android:process=":ui"
Expand Down Expand Up @@ -774,8 +775,7 @@

<activity
android:name="org.microg.gms.googlehelp.ui.GoogleHelpRedirectActivity"
android:process=":ui"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:theme="@style/Theme.App.Translucent"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.googlehelp.HELP" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,118 @@
package org.microg.gms.googlehelp.ui

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcel
import android.os.Parcelable.Creator
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.android.volley.NetworkResponse
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.VolleyError
import com.android.volley.toolbox.Volley
import com.google.android.gms.googlehelp.GoogleHelp
import com.google.android.gms.googlehelp.InProductHelp
import org.microg.gms.googlehelp.CallerAppInfo
import org.microg.gms.googlehelp.DeviceInfo
import org.microg.gms.googlehelp.RequestBody
import org.microg.gms.googlehelp.RequestContent
import org.microg.gms.googlehelp.ResponseContentWarp
import java.util.Locale
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

private const val TAG = "GoogleHelpRedirect"
private const val GOOGLE_HELP_KEY = "EXTRA_GOOGLE_HELP"
private const val PRODUCT_HELP_KEY = "EXTRA_IN_PRODUCT_HELP"

private const val HELP_URL = "https://www.google.com/tools/feedback/mobile/help-suggestions"

class GoogleHelpRedirectActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val callingPackage = callingActivity?.packageName ?: return finish()
val intent = intent ?: return finish()
val googleHelp = intent.getParcelableExtra<GoogleHelp>(EXTRA_GOOGLE_HELP) ?: return finish()
Log.d(TAG, "Using GoogleHelp: $googleHelp")
val uri = googleHelp.uri ?: return finish()
// TODO: Not all Google apps send proper URI values, as these are in fact not used by Google's original implementation.
// As a work-around we should get the proper URL by retrieving top_level_topic_url:$callingPackage
// from https://www.google.com/tools/feedback/mobile/get-configurations endpoint.
// Long-term best is to not redirect to web but instead implement the thing properly, allowing us also to show
// option items, do proper theming for better integration, etc.
Log.d(TAG, "Open $uri for $callingPackage/${googleHelp.appContext} in Browser")
// noinspection UnsafeImplicitIntentLaunch
startActivity(Intent(Intent.ACTION_VIEW, uri))
finish()
Log.d(TAG, "onCreate begin")
if (intent == null) {
Log.d(TAG, "onCreate intent is null")
finish()
return
}
val callingPackage = callingPackage ?: callingActivity?.packageName ?: return finish()
Log.d(TAG, "onCreate callingPackage: $callingPackage")
val googleHelp = intent.getParcelableExtra<GoogleHelp>(GOOGLE_HELP_KEY)
var inProductHelp: InProductHelp? = null
if (googleHelp == null) {
inProductHelp = getParcelableFromIntent<InProductHelp>(intent, PRODUCT_HELP_KEY, InProductHelp.CREATOR)
}

lifecycleScope.launchWhenCreated {
Log.d(TAG, "onCreate: googleHelp: ${googleHelp ?: inProductHelp?.googleHelp}")
val searchId = googleHelp?.appContext ?: inProductHelp?.googleHelp?.appContext
val answerUrl = runCatching { requestHelpLink(callingPackage, searchId).content?.info?.answerUrl }.getOrNull()
Log.d(TAG, "requestHelpLink answerUrl: $answerUrl")
val url = answerUrl ?: googleHelp?.uri?.toString() ?: inProductHelp?.googleHelp?.uri?.toString() ?: return@launchWhenCreated finish()
Log.d(TAG, "Open $url for $callingPackage in Browser")
val targetIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
val resolveInfoList = packageManager.queryIntentActivities(targetIntent, 0)
Log.d(TAG, "resolveInfoList: $resolveInfoList")
if (resolveInfoList.isNotEmpty()) {
startActivity(targetIntent)
}
finish()
}
}

private fun <T> getParcelableFromIntent(intent: Intent, key: String?, creator: Creator<T>): T? {
try {
val data = intent.getByteArrayExtra(key)
if (data != null) {
val parcel = Parcel.obtain()
parcel.unmarshall(data, 0, data.size)
parcel.setDataPosition(0)
val result = creator.createFromParcel(parcel)
parcel.recycle()
return result
}
} catch (e: Exception) {
Log.e(TAG, "Error deserializing InProductHelp", e)
}
return null
}

companion object {
const val EXTRA_GOOGLE_HELP = "EXTRA_GOOGLE_HELP"
private suspend fun requestHelpLink(callingPackage: String, searchId: String?) = suspendCoroutine { sus ->
Volley.newRequestQueue(this.applicationContext).add(object : Request<ResponseContentWarp>(Method.POST, HELP_URL, {
Log.d(TAG, "requestHelpLink: ", it)
sus.resumeWithException(it)
}) {

override fun deliverResponse(response: ResponseContentWarp) {
Log.d(TAG, "requestHelpLink response: $response")
sus.resume(response)
}

override fun getBody(): ByteArray {
return RequestContent.Builder().apply {
appInfo = CallerAppInfo.Builder().apply { packageName = callingPackage }.build()
deviceInfo = DeviceInfo.Builder().apply { language = Locale.getDefault().language }.build()
body = RequestBody.Builder().apply { appContext = searchId }.build()
}.build().also {
Log.d(TAG, "requestBody: $it")
}.encode()
}

override fun getBodyContentType(): String = "application/x-protobuf"

override fun parseNetworkResponse(response: NetworkResponse): Response<ResponseContentWarp> {
return try {
Response.success(ResponseContentWarp.ADAPTER.decode(response.data), null)
} catch (e: Exception) {
Response.error(VolleyError(e))
}
}
})
}
}

0 comments on commit 09cf3c8

Please sign in to comment.