1 /*
2  * Copyright (C) 2017 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.google.android.tv.partner.support;
18 
19 import android.annotation.TargetApi;
20 import android.content.Context;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.content.res.Resources;
24 import android.os.Build;
25 import android.util.Log;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Optional;
29 
30 /**
31  * Abstract class for TV Customization support.
32  *
33  * <p>Implement customization resources as needed in a child class.
34  */
35 @TargetApi(Build.VERSION_CODES.N)
36 @SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
37 public class BaseCustomization {
38     private static final boolean DEBUG = false;
39     private static final String TAG = "BaseCustomization";
40 
41     // TODO move common aosp library
42 
43     // TODO cache resource if performance suffers.
44 
45     private static final String RES_TYPE_BOOLEAN = "bool";
46 
47     private final String packageName;
48 
BaseCustomization(Context context, String[] permissions)49     protected BaseCustomization(Context context, String[] permissions) {
50         packageName = getFirstPackageNameWithPermissions(context, permissions);
51     }
52 
getPackageName()53     public final String getPackageName() {
54         return packageName;
55     }
56 
getFirstPackageNameWithPermissions( Context context, String[] permissions)57     private static String getFirstPackageNameWithPermissions(
58             Context context, String[] permissions) {
59 
60         List<PackageInfo> packageInfos =
61                 context.getPackageManager().getPackagesHoldingPermissions(permissions, 0);
62         if (DEBUG) {
63             Log.d(TAG, "These packages have " + Arrays.toString(permissions) + ": " + packageInfos);
64         }
65         return packageInfos == null || packageInfos.size() == 0
66                 ? ""
67                 : packageInfos.get(0).packageName;
68     }
69 
getResourceForPackage(Context context, String packageName)70     private static Resources getResourceForPackage(Context context, String packageName)
71             throws PackageManager.NameNotFoundException {
72         return context.getPackageManager().getResourcesForApplication(packageName);
73     }
74 
getBooleanResource(Context context, String resourceName)75     public final Optional<Boolean> getBooleanResource(Context context, String resourceName) {
76         if (resourceName.isEmpty()) {
77             return Optional.empty();
78         }
79         try {
80             Resources res = getResourceForPackage(context, packageName);
81             int resId =
82                     res == null
83                             ? 0
84                             : res.getIdentifier(resourceName, RES_TYPE_BOOLEAN, packageName);
85             if (DEBUG) {
86                 Log.d(
87                         TAG,
88                         "Boolean resource  "
89                                 + resourceName
90                                 + " has  "
91                                 + resId
92                                 + " with value "
93                                 + (resId == 0 ? "missing" : res.getBoolean(resId)));
94             }
95             return resId == 0 ? Optional.empty() : Optional.of(res.getBoolean(resId));
96         } catch (PackageManager.NameNotFoundException e) {
97             return Optional.empty();
98         }
99     }
100 }
101