1 /*
2  * Copyright (C) 2022 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.tv.settings.customization;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.graphics.drawable.Drawable;
22 import android.util.Log;
23 
24 import androidx.preference.Preference;
25 
26 import com.android.tv.twopanelsettings.slices.SlicePreference;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 /**
32  * Reads the preference meta-data provided in the customization apk and builds
33  * the listed preferences if any.
34  */
35 final class PartnerResourcesParser {
36     private static final String TAG = "PartnerResourcesParser";
37 
38     private final Context mContext;
39     private final String mSettingsScreen;
40 
41     static final String PREFERENCE_GROUP_END_INDICATOR = "=";
42 
43     /**
44      * Create an instance of the parser for the particular settings screen
45      * @param context TvSettings application context
46      * @param settingsScreen String identifier for the settings screen for which
47      *                      the meta data has to be read
48      */
PartnerResourcesParser(Context context, String settingsScreen)49     PartnerResourcesParser(Context context, String settingsScreen) {
50         mContext = context;
51         mSettingsScreen = settingsScreen;
52     }
53 
buildPreferences()54     public List<Preference> buildPreferences() {
55         final Integer numberOfPreferences = Partner.getInstance(mContext)
56                 .getInteger(String.format("%s_num_prefs", mSettingsScreen));
57         if (numberOfPreferences == null) {
58             Log.i(TAG, "Number of new preferences not provided");
59             return new ArrayList<>();
60         }
61         final List<Preference> preferences = new ArrayList<>(numberOfPreferences);
62         for (int i = 1; i <= numberOfPreferences; i++) {
63             final String name = String.format("%s_pref%d", mSettingsScreen, i);
64             final String uri = Partner.getInstance(mContext).getString(
65                     String.format("%s_uri", name));
66             final String action = Partner.getInstance(mContext).getString(
67                     String.format("%s_intent_action", name));
68             if (uri == null && action == null) {
69                 Log.i(TAG, "Invalid preference, missing uri and action");
70                 continue;
71             }
72             if (uri != null) {
73                 preferences.add(buildSlicePreference(name, uri));
74             } else {
75                 preferences.add(buildPreference(name, action));
76             }
77         }
78         return preferences;
79     }
80 
buildSlicePreference(String name, String uri)81     private SlicePreference buildSlicePreference(String name, String uri) {
82         SlicePreference slicePreference = new SlicePreference(mContext);
83         slicePreference.setUri(uri);
84         final String contentDescription = Partner.getInstance(mContext).getString(
85                 String.format("%s_content_description", name));
86         if (contentDescription != null) {
87             slicePreference.setContentDescription(contentDescription);
88         }
89         parseGenericPreferenceAttributes(name, slicePreference);
90         return slicePreference;
91     }
92 
parseGenericPreferenceAttributes(String name, Preference preference)93     private void parseGenericPreferenceAttributes(String name, Preference preference) {
94         preference.setKey(Partner.getInstance(mContext).getString(
95                 String.format("%s_key", name)));
96         final Drawable icon = Partner.getInstance(mContext).getDrawable(
97                 String.format("%s_icon", name), mContext.getTheme());
98         if (icon != null) {
99             preference.setIcon(icon);
100         }
101         final String title = Partner.getInstance(mContext).getString(
102                 String.format("%s_title", name));
103         if (title != null) {
104             preference.setTitle(title);
105         }
106         final String summary = Partner.getInstance(mContext).getString(
107                 String.format("%s_summary", name));
108         if (summary != null) {
109             preference.setSummary(summary);
110         }
111     }
112 
buildPreference(String name, String action)113     private Preference buildPreference(String name, String action) {
114         final Intent intent = new Intent();
115         intent.setAction(action);
116         final String targetPackage = Partner.getInstance(mContext).getString(
117                 String.format("%s_intent_target_package", name));
118         if (targetPackage != null) {
119             intent.setPackage(targetPackage);
120             final String targetClass = Partner.getInstance(mContext).getString(
121                     String.format("%s_intent_target_class", name));
122             if (targetClass != null) {
123                 intent.setClassName(targetPackage, targetClass);
124             }
125         }
126         final Preference preference = new Preference(mContext);
127         preference.setIntent(intent);
128         parseGenericPreferenceAttributes(name, preference);
129         return preference;
130     }
131 
getOrderedPreferences()132     String[] getOrderedPreferences() {
133         final List<String> orderedPreferences = new ArrayList<>();
134         iteratePreferences(orderedPreferences,
135                 String.format("%s_preferences", mSettingsScreen));
136         return orderedPreferences.toArray(String[]::new);
137     }
138 
iteratePreferences(List<String> orderedPreferences, String preferencesResource)139     private void iteratePreferences(List<String> orderedPreferences, String preferencesResource) {
140         final String[] preferences = Partner.getInstance(mContext).getArray(preferencesResource);
141         if (preferences == null) {
142             Log.i(TAG, "Ordered preference list not found");
143             return;
144         }
145         for (final String preference : preferences) {
146             orderedPreferences.add(preference);
147             // Check to see if it is a PreferenceGroup, in which case, recursively
148             // iterate through the PreferenceGroup to list all its Preferences
149             final String nestedPreferencesResource = String.format(
150                     "%s_%s_preferences", mSettingsScreen, preference);
151             final String[] nestedPreferences = Partner.getInstance(mContext)
152                     .getArray(nestedPreferencesResource);
153             if (nestedPreferences != null && nestedPreferences.length > 0) {
154                 iteratePreferences(orderedPreferences, nestedPreferencesResource);
155             }
156         }
157         // This is necessary to know when a nested PreferenceGroup ends
158         // so the preferences after this are correctly added to the
159         // parent PreferenceGroup
160         orderedPreferences.add(PREFERENCE_GROUP_END_INDICATOR);
161     }
162 }
163