diff options
Diffstat (limited to 'src/com/android/tv/util/Partner.java')
-rw-r--r-- | src/com/android/tv/util/Partner.java | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/com/android/tv/util/Partner.java b/src/com/android/tv/util/Partner.java new file mode 100644 index 00000000..e3688392 --- /dev/null +++ b/src/com/android/tv/util/Partner.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tv.util; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.media.tv.TvInputInfo; +import android.text.TextUtils; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; + +/** + * This file refers to Partner.java in LeanbackLauncher. Interact with partner customizations. There + * can only be one set of customizations on a device, and it must be bundled with the system. + */ +public class Partner { + private static final String TAG = "Partner"; + /** Marker action used to discover partner */ + private static final String ACTION_PARTNER_CUSTOMIZATION = + "com.google.android.leanbacklauncher.action.PARTNER_CUSTOMIZATION"; + + /** ID tags for device input types */ + public static final String INPUT_TYPE_BUNDLED_TUNER = "input_type_combined_tuners"; + public static final String INPUT_TYPE_TUNER = "input_type_tuner"; + public static final String INPUT_TYPE_CEC_LOGICAL = "input_type_cec_logical"; + public static final String INPUT_TYPE_CEC_RECORDER = "input_type_cec_recorder"; + public static final String INPUT_TYPE_CEC_PLAYBACK = "input_type_cec_playback"; + public static final String INPUT_TYPE_MHL_MOBILE = "input_type_mhl_mobile"; + public static final String INPUT_TYPE_HDMI = "input_type_hdmi"; + public static final String INPUT_TYPE_DVI = "input_type_dvi"; + public static final String INPUT_TYPE_COMPONENT = "input_type_component"; + public static final String INPUT_TYPE_SVIDEO = "input_type_svideo"; + public static final String INPUT_TYPE_COMPOSITE = "input_type_composite"; + public static final String INPUT_TYPE_DISPLAY_PORT = "input_type_displayport"; + public static final String INPUT_TYPE_VGA = "input_type_vga"; + public static final String INPUT_TYPE_SCART = "input_type_scart"; + public static final String INPUT_TYPE_OTHER = "input_type_other"; + + private static final String INPUTS_ORDER = "home_screen_inputs_ordering"; + private static final String TYPE_ARRAY = "array"; + + private static Partner sPartner; + private static final Object sLock = new Object(); + + private final String mPackageName; + private final String mReceiverName; + private final Resources mResources; + + private static final Map<String, Integer> INPUT_TYPE_MAP = new HashMap<>(); + static { + INPUT_TYPE_MAP.put(INPUT_TYPE_BUNDLED_TUNER, TvInputManagerHelper.TYPE_BUNDLED_TUNER); + INPUT_TYPE_MAP.put(INPUT_TYPE_TUNER, TvInputInfo.TYPE_TUNER); + 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); + 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); + INPUT_TYPE_MAP.put(INPUT_TYPE_HDMI, TvInputInfo.TYPE_HDMI); + INPUT_TYPE_MAP.put(INPUT_TYPE_DVI, TvInputInfo.TYPE_DVI); + INPUT_TYPE_MAP.put(INPUT_TYPE_COMPONENT, TvInputInfo.TYPE_COMPONENT); + INPUT_TYPE_MAP.put(INPUT_TYPE_SVIDEO, TvInputInfo.TYPE_SVIDEO); + INPUT_TYPE_MAP.put(INPUT_TYPE_COMPOSITE, TvInputInfo.TYPE_COMPOSITE); + INPUT_TYPE_MAP.put(INPUT_TYPE_DISPLAY_PORT, TvInputInfo.TYPE_DISPLAY_PORT); + INPUT_TYPE_MAP.put(INPUT_TYPE_VGA, TvInputInfo.TYPE_VGA); + INPUT_TYPE_MAP.put(INPUT_TYPE_SCART, TvInputInfo.TYPE_SCART); + INPUT_TYPE_MAP.put(INPUT_TYPE_OTHER, TvInputInfo.TYPE_OTHER); + } + + private Partner(String packageName, String receiverName, Resources res) { + mPackageName = packageName; + mReceiverName = receiverName; + mResources = res; + } + + /** Returns partner instance. */ + public static Partner getInstance(Context context) { + PackageManager pm = context.getPackageManager(); + synchronized (sLock) { + ResolveInfo info = getPartnerResolveInfo(pm); + if (info != null) { + final String packageName = info.activityInfo.packageName; + final String receiverName = info.activityInfo.name; + try { + final Resources res = pm.getResourcesForApplication(packageName); + sPartner = new Partner(packageName, receiverName, res); + sPartner.sendInitBroadcast(context); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Failed to find resources for " + packageName); + } + } + if (sPartner == null) { + sPartner = new Partner(null, null, null); + } + } + return sPartner; + } + + /** Resets the Partner instance to handle the partner package has changed. */ + public static void reset(Context context, String packageName) { + synchronized (sLock) { + if (sPartner != null && !TextUtils.isEmpty(packageName)) { + if (packageName.equals(sPartner.mPackageName)) { + // Force a refresh, so we send an Init to the updated package + sPartner = null; + getInstance(context); + } + } + } + } + + /** This method is used to send init broadcast to the new/changed partner package. */ + private void sendInitBroadcast(Context context) { + if (!TextUtils.isEmpty(mPackageName) && !TextUtils.isEmpty(mReceiverName)) { + Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION); + final ComponentName componentName = new ComponentName(mPackageName, mReceiverName); + intent.setComponent(componentName); + intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); + context.sendBroadcast(intent); + } + } + + /** Returns the order of inputs. */ + public Map<Integer, Integer> getInputsOrderMap() { + HashMap<Integer, Integer> map = new HashMap<>(); + if (mResources != null && !TextUtils.isEmpty(mPackageName)) { + String[] inputsArray = null; + final int resId = mResources.getIdentifier(INPUTS_ORDER, TYPE_ARRAY, mPackageName); + if (resId != 0) { + inputsArray = mResources.getStringArray(resId); + } + if (inputsArray != null) { + int priority = 0; + for (String input : inputsArray) { + Integer type = INPUT_TYPE_MAP.get(input); + if (type != null) { + map.put(type, priority++); + } + } + } + } + return map; + } + + private static ResolveInfo getPartnerResolveInfo(PackageManager pm) { + final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION); + ResolveInfo partnerInfo = null; + for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) { + if (isSystemApp(info)) { + partnerInfo = info; + break; + } + } + return partnerInfo; + } + + protected static boolean isSystemApp(ResolveInfo info) { + return (info.activityInfo != null + && info.activityInfo.applicationInfo != null + && (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + } +} |