• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.android.tv.util;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.content.res.Resources;
26 import android.media.tv.TvInputInfo;
27 import android.text.TextUtils;
28 import android.util.Log;
29 
30 import java.util.HashMap;
31 import java.util.Map;
32 
33 /**
34  * This file refers to Partner.java in LeanbackLauncher. Interact with partner customizations. There
35  * can only be one set of customizations on a device, and it must be bundled with the system.
36  */
37 public class Partner {
38     private static final String TAG = "Partner";
39     /** Marker action used to discover partner */
40     private static final String ACTION_PARTNER_CUSTOMIZATION =
41             "com.google.android.leanbacklauncher.action.PARTNER_CUSTOMIZATION";
42 
43     /** ID tags for device input types */
44     public static final String INPUT_TYPE_BUNDLED_TUNER = "input_type_combined_tuners";
45     public static final String INPUT_TYPE_TUNER = "input_type_tuner";
46     public static final String INPUT_TYPE_CEC_LOGICAL = "input_type_cec_logical";
47     public static final String INPUT_TYPE_CEC_RECORDER = "input_type_cec_recorder";
48     public static final String INPUT_TYPE_CEC_PLAYBACK = "input_type_cec_playback";
49     public static final String INPUT_TYPE_MHL_MOBILE = "input_type_mhl_mobile";
50     public static final String INPUT_TYPE_HDMI = "input_type_hdmi";
51     public static final String INPUT_TYPE_DVI = "input_type_dvi";
52     public static final String INPUT_TYPE_COMPONENT = "input_type_component";
53     public static final String INPUT_TYPE_SVIDEO = "input_type_svideo";
54     public static final String INPUT_TYPE_COMPOSITE = "input_type_composite";
55     public static final String INPUT_TYPE_DISPLAY_PORT = "input_type_displayport";
56     public static final String INPUT_TYPE_VGA = "input_type_vga";
57     public static final String INPUT_TYPE_SCART = "input_type_scart";
58     public static final String INPUT_TYPE_OTHER = "input_type_other";
59 
60     private static final String INPUTS_ORDER = "home_screen_inputs_ordering";
61     private static final String TYPE_ARRAY = "array";
62 
63     private static Partner sPartner;
64     private static final Object sLock = new Object();
65 
66     private final String mPackageName;
67     private final String mReceiverName;
68     private final Resources mResources;
69 
70     private static final Map<String, Integer> INPUT_TYPE_MAP = new HashMap<>();
71     static {
INPUT_TYPE_MAP.put(INPUT_TYPE_BUNDLED_TUNER, TvInputManagerHelper.TYPE_BUNDLED_TUNER)72         INPUT_TYPE_MAP.put(INPUT_TYPE_BUNDLED_TUNER, TvInputManagerHelper.TYPE_BUNDLED_TUNER);
INPUT_TYPE_MAP.put(INPUT_TYPE_TUNER, TvInputInfo.TYPE_TUNER)73         INPUT_TYPE_MAP.put(INPUT_TYPE_TUNER, TvInputInfo.TYPE_TUNER);
INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_LOGICAL, TvInputManagerHelper.TYPE_CEC_DEVICE)74         INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_LOGICAL, TvInputManagerHelper.TYPE_CEC_DEVICE);
INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_RECORDER, TvInputManagerHelper.TYPE_CEC_DEVICE_RECORDER)75         INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_RECORDER, TvInputManagerHelper.TYPE_CEC_DEVICE_RECORDER);
INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_PLAYBACK, TvInputManagerHelper.TYPE_CEC_DEVICE_PLAYBACK)76         INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_PLAYBACK, TvInputManagerHelper.TYPE_CEC_DEVICE_PLAYBACK);
INPUT_TYPE_MAP.put(INPUT_TYPE_MHL_MOBILE, TvInputManagerHelper.TYPE_MHL_MOBILE)77         INPUT_TYPE_MAP.put(INPUT_TYPE_MHL_MOBILE, TvInputManagerHelper.TYPE_MHL_MOBILE);
INPUT_TYPE_MAP.put(INPUT_TYPE_HDMI, TvInputInfo.TYPE_HDMI)78         INPUT_TYPE_MAP.put(INPUT_TYPE_HDMI, TvInputInfo.TYPE_HDMI);
INPUT_TYPE_MAP.put(INPUT_TYPE_DVI, TvInputInfo.TYPE_DVI)79         INPUT_TYPE_MAP.put(INPUT_TYPE_DVI, TvInputInfo.TYPE_DVI);
INPUT_TYPE_MAP.put(INPUT_TYPE_COMPONENT, TvInputInfo.TYPE_COMPONENT)80         INPUT_TYPE_MAP.put(INPUT_TYPE_COMPONENT, TvInputInfo.TYPE_COMPONENT);
INPUT_TYPE_MAP.put(INPUT_TYPE_SVIDEO, TvInputInfo.TYPE_SVIDEO)81         INPUT_TYPE_MAP.put(INPUT_TYPE_SVIDEO, TvInputInfo.TYPE_SVIDEO);
INPUT_TYPE_MAP.put(INPUT_TYPE_COMPOSITE, TvInputInfo.TYPE_COMPOSITE)82         INPUT_TYPE_MAP.put(INPUT_TYPE_COMPOSITE, TvInputInfo.TYPE_COMPOSITE);
INPUT_TYPE_MAP.put(INPUT_TYPE_DISPLAY_PORT, TvInputInfo.TYPE_DISPLAY_PORT)83         INPUT_TYPE_MAP.put(INPUT_TYPE_DISPLAY_PORT, TvInputInfo.TYPE_DISPLAY_PORT);
INPUT_TYPE_MAP.put(INPUT_TYPE_VGA, TvInputInfo.TYPE_VGA)84         INPUT_TYPE_MAP.put(INPUT_TYPE_VGA, TvInputInfo.TYPE_VGA);
INPUT_TYPE_MAP.put(INPUT_TYPE_SCART, TvInputInfo.TYPE_SCART)85         INPUT_TYPE_MAP.put(INPUT_TYPE_SCART, TvInputInfo.TYPE_SCART);
INPUT_TYPE_MAP.put(INPUT_TYPE_OTHER, TvInputInfo.TYPE_OTHER)86         INPUT_TYPE_MAP.put(INPUT_TYPE_OTHER, TvInputInfo.TYPE_OTHER);
87     }
88 
Partner(String packageName, String receiverName, Resources res)89     private Partner(String packageName, String receiverName, Resources res) {
90         mPackageName = packageName;
91         mReceiverName = receiverName;
92         mResources = res;
93     }
94 
95     /** Returns partner instance. */
getInstance(Context context)96     public static Partner getInstance(Context context) {
97         PackageManager pm = context.getPackageManager();
98         synchronized (sLock) {
99             ResolveInfo info = getPartnerResolveInfo(pm);
100             if (info != null) {
101                 final String packageName = info.activityInfo.packageName;
102                 final String receiverName = info.activityInfo.name;
103                 try {
104                     final Resources res = pm.getResourcesForApplication(packageName);
105                     sPartner = new Partner(packageName, receiverName, res);
106                     sPartner.sendInitBroadcast(context);
107                 } catch (PackageManager.NameNotFoundException e) {
108                     Log.w(TAG, "Failed to find resources for " + packageName);
109                 }
110             }
111             if (sPartner == null) {
112                 sPartner = new Partner(null, null, null);
113             }
114         }
115         return sPartner;
116     }
117 
118     /** Resets the Partner instance to handle the partner package has changed. */
reset(Context context, String packageName)119     public static void reset(Context context, String packageName) {
120         synchronized (sLock) {
121             if (sPartner != null && !TextUtils.isEmpty(packageName)) {
122                 if (packageName.equals(sPartner.mPackageName)) {
123                     // Force a refresh, so we send an Init to the updated package
124                     sPartner = null;
125                     getInstance(context);
126                 }
127             }
128         }
129     }
130 
131     /** This method is used to send init broadcast to the new/changed partner package. */
sendInitBroadcast(Context context)132     private void sendInitBroadcast(Context context) {
133         if (!TextUtils.isEmpty(mPackageName) && !TextUtils.isEmpty(mReceiverName)) {
134             Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
135             final ComponentName componentName = new ComponentName(mPackageName, mReceiverName);
136             intent.setComponent(componentName);
137             intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
138             context.sendBroadcast(intent);
139         }
140     }
141 
142     /** Returns the order of inputs. */
getInputsOrderMap()143     public Map<Integer, Integer> getInputsOrderMap() {
144         HashMap<Integer, Integer> map = new HashMap<>();
145         if (mResources != null && !TextUtils.isEmpty(mPackageName)) {
146             String[] inputsArray = null;
147             final int resId = mResources.getIdentifier(INPUTS_ORDER, TYPE_ARRAY, mPackageName);
148             if (resId != 0) {
149                 inputsArray = mResources.getStringArray(resId);
150             }
151             if (inputsArray != null) {
152                 int priority = 0;
153                 for (String input : inputsArray) {
154                     Integer type = INPUT_TYPE_MAP.get(input);
155                     if (type != null) {
156                         map.put(type, priority++);
157                     }
158                 }
159             }
160         }
161         return map;
162     }
163 
getPartnerResolveInfo(PackageManager pm)164     private static ResolveInfo getPartnerResolveInfo(PackageManager pm) {
165         final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
166         ResolveInfo partnerInfo = null;
167         for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) {
168             if (isSystemApp(info)) {
169                 partnerInfo = info;
170                 break;
171             }
172         }
173         return partnerInfo;
174     }
175 
isSystemApp(ResolveInfo info)176     protected static boolean isSystemApp(ResolveInfo info) {
177         return (info.activityInfo != null
178                 && info.activityInfo.applicationInfo != null
179                 && (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
180     }
181 }
182