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