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