From 6afa25df8bf1ed2fd60237cc9fbaf3d635375cca Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Fri, 16 Aug 2024 15:12:40 +0800 Subject: [PATCH] Encode SpaSearchLandingKey with Base64 To ensure the landing key is the same as the indexing key. Bug: 358238959 Flag: EXEMPT bug fix Test: manual - search roaming Test: unit test Change-Id: I26ce712feaa83e9e70a3eb39039e5c3527f24cca --- .../spa/search/SpaSearchLandingActivity.kt | 14 +---- .../spa/search/SpaSearchLandingKeyExt.kt | 34 +++++++++++ .../spa/search/SpaSearchRepository.kt | 2 +- .../MobileNetworkSettingsSearchIndexTest.kt | 4 +- .../search/SpaSearchLandingActivityTest.kt | 4 +- .../spa/search/SpaSearchLandingKeyExtTest.kt | 57 +++++++++++++++++++ .../spa/search/SpaSearchRepositoryTest.kt | 3 +- 7 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 src/com/android/settings/spa/search/SpaSearchLandingKeyExt.kt create mode 100644 tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingKeyExtTest.kt diff --git a/src/com/android/settings/spa/search/SpaSearchLandingActivity.kt b/src/com/android/settings/spa/search/SpaSearchLandingActivity.kt index cb5f745cd41..2c0955b42b0 100644 --- a/src/com/android/settings/spa/search/SpaSearchLandingActivity.kt +++ b/src/com/android/settings/spa/search/SpaSearchLandingActivity.kt @@ -27,9 +27,6 @@ import com.android.settings.core.SubSettingLauncher import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settings.password.PasswordUtils import com.android.settings.spa.SpaDestination -import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey -import com.google.protobuf.ByteString -import com.google.protobuf.InvalidProtocolBufferException class SpaSearchLandingActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -48,22 +45,17 @@ class SpaSearchLandingActivity : Activity() { companion object { @VisibleForTesting fun tryLaunch(context: Context, keyString: String) { - val key = - try { - SpaSearchLandingKey.parseFrom(ByteString.copyFromUtf8(keyString)) - } catch (e: InvalidProtocolBufferException) { - Log.w(TAG, "arg key ($keyString) invalid", e) - return - } - + val key = decodeToSpaSearchLandingKey(keyString) ?: return if (key.hasSpaPage()) { val destination = key.spaPage.destination if (destination.isNotEmpty()) { + Log.d(TAG, "Launch SPA search result: ${key.spaPage}") SpaDestination(destination = destination, highlightMenuKey = null) .startFromExportedActivity(context) } } if (key.hasFragment()) { + Log.d(TAG, "Launch fragment search result: ${key.fragment}") val arguments = Bundle().apply { key.fragment.argumentsMap.forEach { (k, v) -> diff --git a/src/com/android/settings/spa/search/SpaSearchLandingKeyExt.kt b/src/com/android/settings/spa/search/SpaSearchLandingKeyExt.kt new file mode 100644 index 00000000000..9540d9bed24 --- /dev/null +++ b/src/com/android/settings/spa/search/SpaSearchLandingKeyExt.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +package com.android.settings.spa.search + +import android.util.Base64 +import android.util.Log +import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey + +private const val TAG = "SpaSearchLandingKeyExt" + +fun SpaSearchLandingKey.encodeToString(): String = + Base64.encodeToString(toByteArray(), Base64.DEFAULT) + +fun decodeToSpaSearchLandingKey(input: String): SpaSearchLandingKey? = + try { + SpaSearchLandingKey.parseFrom(Base64.decode(input, Base64.DEFAULT)) + } catch (e: Exception) { + Log.w(TAG, "SpaSearchLandingKey ($input) invalid", e) + null + } diff --git a/src/com/android/settings/spa/search/SpaSearchRepository.kt b/src/com/android/settings/spa/search/SpaSearchRepository.kt index e5334dd2d8a..b1003ae8c3f 100644 --- a/src/com/android/settings/spa/search/SpaSearchRepository.kt +++ b/src/com/android/settings/spa/search/SpaSearchRepository.kt @@ -96,7 +96,7 @@ class SpaSearchRepository( keywords: String? = null, ) = SearchIndexableRaw(context).apply { - key = spaSearchLandingKey.toByteString().toStringUtf8() + key = spaSearchLandingKey.encodeToString() title = itemTitle this.keywords = keywords intentAction = SEARCH_LANDING_ACTION diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt index bf5120817c1..ad50433c24c 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndexTest.kt @@ -30,8 +30,8 @@ import com.android.settings.spa.SpaSearchLanding.BundleValue import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey import com.android.settings.spa.search.SpaSearchLandingActivity +import com.android.settings.spa.search.decodeToSpaSearchLandingKey import com.google.common.truth.Truth.assertThat -import com.google.protobuf.ByteString import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -104,7 +104,7 @@ class MobileNetworkSettingsSearchIndexTest { searchIndexableData.searchIndexProvider.getDynamicRawDataToIndex(context, true) assertThat(dynamicRawDataToIndex).hasSize(1) val rawData = dynamicRawDataToIndex[0] - val key = SpaSearchLandingKey.parseFrom(ByteString.copyFromUtf8(rawData.key)) + val key = decodeToSpaSearchLandingKey(rawData.key) assertThat(key) .isEqualTo( SpaSearchLandingKey.newBuilder() diff --git a/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingActivityTest.kt index 7410bb42266..6fb4b84b3db 100644 --- a/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingActivityTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingActivityTest.kt @@ -52,7 +52,7 @@ class SpaSearchLandingActivityTest { .setSpaPage(SpaSearchLandingSpaPage.newBuilder().setDestination(DESTINATION)) .build() - SpaSearchLandingActivity.tryLaunch(context, key.toByteString().toStringUtf8()) + SpaSearchLandingActivity.tryLaunch(context, key.encodeToString()) verify(context).startActivity(argThat { getStringExtra(KEY_DESTINATION) == DESTINATION }) } @@ -70,7 +70,7 @@ class SpaSearchLandingActivityTest { BundleValue.newBuilder().setIntValue(ARGUMENT_VALUE).build())) .build() - SpaSearchLandingActivity.tryLaunch(context, key.toByteString().toStringUtf8()) + SpaSearchLandingActivity.tryLaunch(context, key.encodeToString()) val intent = argumentCaptor { verify(context).startActivity(capture()) }.firstValue assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) diff --git a/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingKeyExtTest.kt b/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingKeyExtTest.kt new file mode 100644 index 00000000000..f4a9ce64882 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchLandingKeyExtTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * 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 + * + * http://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. + */ + +package com.android.settings.spa.search + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.spa.SpaSearchLanding.BundleValue +import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment +import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SpaSearchLandingKeyExtTest { + + @Test + fun encodeToString_thenDecode_shouldDecodeCorrectly() { + val encoded = KEY.encodeToString() + + val decoded = decodeToSpaSearchLandingKey(encoded) + + assertThat(decoded).isEqualTo(KEY) + } + + @Test + fun decodeToSpaSearchLandingKey_badString_shouldReturnNull() { + val decoded = decodeToSpaSearchLandingKey("bad") + + assertThat(decoded).isNull() + } + + private companion object { + val KEY: SpaSearchLandingKey = + SpaSearchLandingKey.newBuilder() + .setFragment( + SpaSearchLandingFragment.newBuilder() + .setFragmentName("Destination") + .setPreferenceKey("preference_key") + .putArguments( + "argument_key", BundleValue.newBuilder().setIntValue(123).build())) + .build() + } +} diff --git a/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchRepositoryTest.kt index c38f22f129b..f97abe400f8 100644 --- a/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/search/SpaSearchRepositoryTest.kt @@ -23,7 +23,6 @@ import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingSpaPage import com.android.settings.spa.search.SpaSearchRepository.Companion.createSearchIndexableData import com.android.settingslib.spa.framework.common.SettingsPageProvider import com.google.common.truth.Truth.assertThat -import com.google.protobuf.ByteString import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @@ -46,7 +45,7 @@ class SpaSearchRepositoryTest { assertThat(searchIndexableData.targetClass).isEqualTo(pageProvider::class.java) assertThat(dynamicRawDataToIndex).hasSize(1) val rawData = dynamicRawDataToIndex[0] - val key = SpaSearchLandingKey.parseFrom(ByteString.copyFromUtf8(rawData.key)) + val key = decodeToSpaSearchLandingKey(rawData.key) assertThat(key) .isEqualTo( SpaSearchLandingKey.newBuilder()