Skip to content

Commit

Permalink
Fetch bulk details for apps retrieved from policy
Browse files Browse the repository at this point in the history
Nonfunctional attempt.
  • Loading branch information
fynngodau committed Sep 15, 2024
1 parent 0db6eed commit c621098
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 29 deletions.
4 changes: 3 additions & 1 deletion vending-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,9 @@
android:name="com.google.android.finsky.splitinstallservice.SplitInstallManager$InstallResultReceiver"
android:exported="true"/>
<activity android:name="org.microg.vending.ui.VendingActivity"
android:exported="true">
android:exported="true"
android:theme="@style/Theme.Material3.DayNight"
android:label="@string/vending_activity_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class GooglePlayApi {
const val URL_GET_PURCHASE_HISTORY = "$URL_FDFE/inAppPurchaseHistory"
const val URL_AUTH_PROOF_TOKENS = "https://www.googleapis.com/reauth/v1beta/users/me/reauthProofTokens"
const val URL_DETAILS = "$URL_FDFE/details"
const val URL_BULK_DETAILS = "$URL_FDFE/bulkDetails"
const val URL_PURCHASE = "$URL_FDFE/purchase"
const val URL_ENTERPRISE_CLIENT_POLICY = "$URL_FDFE/getEnterpriseClientPolicy"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ open class App(
val packageName: String,
val displayName: String,
val state: State,
val iconUrl: String
val iconUrl: String?
) {
enum class State {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ class EnterpriseApp(
packageName: String,
displayName: String,
state: State,
iconUrl: String,
iconUrl: String?,
val policy: AppInstallPolicy,
) : App(packageName, displayName, state, iconUrl)
117 changes: 93 additions & 24 deletions vending-app/src/main/java/org/microg/vending/ui/VendingActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,56 @@ import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.android.vending.R
import com.android.vending.buildRequestHeaders
import com.android.volley.VolleyError
import com.google.android.finsky.BulkDetailsRequest
import com.google.android.finsky.DetailsRequest
import com.google.android.finsky.GoogleApiResponse
import kotlinx.coroutines.runBlocking
import org.microg.gms.profile.ProfileManager
import org.microg.gms.ui.TAG
import org.microg.vending.billing.AuthManager
import org.microg.vending.billing.TAG
import org.microg.vending.billing.core.GooglePlayApi.Companion.URL_BULK_DETAILS
import org.microg.vending.billing.core.GooglePlayApi.Companion.URL_DETAILS
import org.microg.vending.billing.core.GooglePlayApi.Companion.URL_ENTERPRISE_CLIENT_POLICY
import org.microg.vending.billing.core.HttpClient
import org.microg.vending.billing.createDeviceEnvInfo
import org.microg.vending.billing.proto.ResponseWrapper
import org.microg.vending.enterprise.App
import org.microg.vending.enterprise.EnterpriseApp
import java.io.IOException


class VendingActivity : ComponentActivity() {

var apps: MutableList<EnterpriseApp> = mutableStateListOf()
var networkState by mutableStateOf(NetworkState.ACTIVE)

@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)

ProfileManager.ensureInitialized(this)
Expand All @@ -40,51 +63,97 @@ class VendingActivity : ComponentActivity() {
val account = am.getAccountsByType("com.google.work").first()!!
Thread {
runBlocking {
val authData = AuthManager.getAuthData(this@VendingActivity, account)
val deviceInfo = createDeviceEnvInfo(this@VendingActivity)
if (deviceInfo == null || authData == null) {
Log.e(TAG, "Unable to open play store when deviceInfo = $deviceInfo and authData = $authData")
return@runBlocking
}
try {
val authData = AuthManager.getAuthData(this@VendingActivity, account)
val deviceInfo = createDeviceEnvInfo(this@VendingActivity)
if (deviceInfo == null || authData == null) {
Log.e(TAG, "Unable to open play store when deviceInfo = $deviceInfo and authData = $authData")
networkState = NetworkState.ERROR
return@runBlocking
}

val headers = buildRequestHeaders(authData.authToken, authData.gsfId.toLong(16))
.plus("content-type" to "application/x-protobuf")
val client = HttpClient(this@VendingActivity)
val headers = buildRequestHeaders(authData.authToken, authData.gsfId.toLong(16))
val client = HttpClient(this@VendingActivity)

try {
val apps = client.post(
url = URL_ENTERPRISE_CLIENT_POLICY,
headers = headers,
headers = headers.plus("content-type" to "application/x-protobuf"),
adapter = GoogleApiResponse.ADAPTER
).response?.enterpriseClientPolicyResult?.policy?.apps?.filter { it.packageName != null && it.policy != null }
?.map {

if (apps == null) {
Log.e(TAG, "unexpected network response: missing expected fields")
networkState = NetworkState.ERROR
return@runBlocking
}

val details = client.post(
url = URL_BULK_DETAILS,
headers = headers,
adapter = GoogleApiResponse.ADAPTER,
payload = BulkDetailsRequest(
apps.map {
DetailsRequest(
packageName = it.packageName!!,
versionCode = 0,
unknown0 = 0
)
}
)).response?.bulkDetailsResponse?.details?.mapNotNull { it.metadata }
?.filter { it.packageName != null && it.displayName != null }?.map { app ->
EnterpriseApp(
it.packageName!!,
"Display name placeholder",
app.packageName!!,
app.displayName!!,
App.State.NOT_INSTALLED,
"https://i.ytimg.com/vi/IWZFLZ1mvc4/hqdefault.jpg",
it.policy!!
app.icon.lastOrNull()?.url,
apps.find { it.packageName!! == app.packageName }!!.policy!!,
)
}

this@VendingActivity.apps.apply {
clear()
apps?.let { addAll(it) }
details?.let { addAll(it) }
}
networkState = NetworkState.PASSIVE
} catch (e: IOException) {
networkState = NetworkState.ERROR
} catch (e: VolleyError) {
networkState = NetworkState.ERROR
}
}
}.start()



setContent {
MaterialTheme {
Column {
Text(account.name)
NetworkStateComponent(networkState, { TODO("reload") }) {
EnterpriseListComponent(apps)
Scaffold(
topBar = {
TopAppBar(
title = {
Row {
Icon(
painterResource(R.drawable.ic_work),
contentDescription = null,
Modifier.align(Alignment.CenterVertically),
tint = LocalContentColor.current
)
Text(stringResource(R.string.vending_activity_name),
Modifier
.align(Alignment.CenterVertically)
.padding(start = 8.dp)
)
}
},
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.primary
)
)
}
) { innerPadding ->
Column(Modifier.padding(innerPadding)) {
NetworkStateComponent(networkState, { TODO("reload") }) {
EnterpriseListComponent(apps)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fun buildRequestHeaders(auth: String, androidId: Long, language: List<String> ?=
DeviceMeta.Builder().android(
AndroidVersionMeta.Builder().androidSdk(Build.VERSION.SDK_INT).buildNumber(Build.ID).androidVersion(Build.VERSION.RELEASE).unknown(0).build()
).unknown1(
UnknownByte12.Builder().bytes(ByteString.EMPTY).build()
UnknownByte12.Builder().bytes(ByteString.EMPTY).build().toString()
).unknown2(1).build()
).userAgent(
UserAgent.Builder().deviceName(Build.DEVICE).deviceHardware(Build.HARDWARE).deviceModelName(Build.MODEL).finskyVersion(FINSKY_VERSION)
Expand Down
15 changes: 15 additions & 0 deletions vending-app/src/main/proto/BulkDetailsRequest.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
syntax = "proto2";

option java_package = "com.google.android.finsky";
option java_multiple_files = true;


message BulkDetailsRequest {
repeated DetailsRequest requests = 8;
}

message DetailsRequest {
required string packageName = 1;
optional uint32 versionCode = 2;
required uint32 unknown0 = 3; // = 0
}
29 changes: 29 additions & 0 deletions vending-app/src/main/proto/BulkDetailsResponse.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
syntax = "proto3";

option java_package = "com.google.android.finsky";
option java_multiple_files = true;

message BulkAppDetailsResponse {
repeated AppDetail details = 1;
}

message AppDetail {
optional AppMetadata metadata = 1;
}

message AppMetadata {
optional string packageName = 1; // duplicated at ID 2
optional string displayName = 5;
optional string author = 6;
repeated Icon icon = 10;
}

message Icon {
optional Resolution resolution = 2;
string url = 5;
}

message Resolution {
optional uint32 width = 3;
optional uint32 height = 4;
}
2 changes: 1 addition & 1 deletion vending-app/src/main/proto/RequestHeader.proto
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ message RequestLanguagePackage {

message DeviceMeta {
optional AndroidVersionMeta android = 1;
optional UnknownByte12 unknown1 = 2;
optional string unknown1 = 2; // inconsistent observations; a field of type "UnknownByte12" was observed as well
optional uint32 unknown2 = 3; // observed value: 1

}
Expand Down
2 changes: 2 additions & 0 deletions vending-app/src/main/proto/SplitInstall.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ option java_package = "com.google.android.finsky";
option java_multiple_files = true;

import "EnterpriseClientPolicy.proto";
import "BulkDetailsResponse.proto";

message GoogleApiResponse {
optional ApiResponse response = 1;
Expand All @@ -16,6 +17,7 @@ message UnknownType {

message ApiResponse {
optional TocResponse tocApi = 6;
optional BulkAppDetailsResponse bulkDetailsResponse = 19;
optional SplitResponse splitReqResult = 21;
optional EnterpriseClientPolicyResponse enterpriseClientPolicyResult = 135;
// optional SyncApiResp syncResult = 183;
Expand Down
5 changes: 5 additions & 0 deletions vending-app/src/main/res/drawable/ic_work.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#4285F4" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">

<path android:fillColor="@android:color/white" android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z"/>

</vector>
1 change: 1 addition & 0 deletions vending-app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<string name="license_notification_sign_in">Sign In</string>
<string name="license_notification_ignore">Ignore</string>

<string name="vending_activity_name">Work app store</string>
<string name="vending_overview_enterprise_row_mandatory">Installation required</string>
<string name="vending_overview_enterprise_row_mandatory_hint">Your administrator requires that you install these apps on your managed device.</string>
<string name="vending_overview_enterprise_row_mandatory_missing_hint">Your device is missing mandatory apps chosen by your administrator.</string>
Expand Down

0 comments on commit c621098

Please sign in to comment.