• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wm.shell.apptoweb
18 
19 import android.content.Context
20 import android.provider.DeviceConfig
21 import android.webkit.URLUtil
22 import com.android.internal.annotations.VisibleForTesting
23 import com.android.wm.shell.R
24 import com.android.wm.shell.common.ShellExecutor
25 import com.android.wm.shell.shared.annotations.ShellMainThread
26 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useAppToWebBuildTimeGenericLinks
27 
28 /**
29  * Retrieves the build-time or server-side generic links list and parses and stores the
30  * package-to-url pairs.
31  */
32 class AppToWebGenericLinksParser(
33     private val context: Context,
34     @ShellMainThread private val mainExecutor: ShellExecutor
35 ) {
36     private val genericLinksMap: MutableMap<String, String> = mutableMapOf()
37 
38     init {
39         // If using the server-side generic links list, register a listener
40         if (!useAppToWebBuildTimeGenericLinks()) {
41             DeviceConfigListener()
42         }
43 
44         updateGenericLinksMap()
45     }
46 
47     /** Returns the generic link associated with the [packageName] or null if there is none. */
getGenericLinknull48     fun getGenericLink(packageName: String): String? = genericLinksMap[packageName]
49 
50     private fun updateGenericLinksMap() {
51         val genericLinksList =
52             if (useAppToWebBuildTimeGenericLinks()) {
53                 context.resources.getString(R.string.generic_links_list)
54             } else {
55                 DeviceConfig.getString(NAMESPACE, FLAG_GENERIC_LINKS, /* defaultValue= */ "")
56             } ?: return
57 
58         parseGenericLinkList(genericLinksList)
59     }
60 
parseGenericLinkListnull61     private fun parseGenericLinkList(genericLinksList: String) {
62         val newEntries =
63             genericLinksList
64                 .split(" ")
65                 .filter { it.contains(':') }
66                 .map {
67                     val (packageName, url) = it.split(':', limit = 2)
68                     return@map packageName to url
69                 }
70                 .filter { URLUtil.isNetworkUrl(it.second) }
71 
72         genericLinksMap.clear()
73         genericLinksMap.putAll(newEntries)
74     }
75 
76     /**
77      * Listens for changes to the server-side generic links list and updates the package to url map
78      * if [DesktopModeStatus#useBuildTimeGenericLinkList()] is set to false.
79      */
80     inner class DeviceConfigListener : DeviceConfig.OnPropertiesChangedListener {
81         init {
82             DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, mainExecutor, this)
83         }
84 
onPropertiesChangednull85         override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
86             if (properties.keyset.contains(FLAG_GENERIC_LINKS)) {
87                 updateGenericLinksMap()
88             }
89         }
90     }
91 
92     companion object {
93         private const val NAMESPACE = DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES
94         @VisibleForTesting const val FLAG_GENERIC_LINKS = "generic_links_flag"
95     }
96 }
97