Home | History | Annotate | Download | only in util
      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 {
     72         INPUT_TYPE_MAP.put(INPUT_TYPE_BUNDLED_TUNER, TvInputManagerHelper.TYPE_BUNDLED_TUNER);
     73         INPUT_TYPE_MAP.put(INPUT_TYPE_TUNER, TvInputInfo.TYPE_TUNER);
     74         INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_LOGICAL, TvInputManagerHelper.TYPE_CEC_DEVICE);
     75         INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_RECORDER, TvInputManagerHelper.TYPE_CEC_DEVICE_RECORDER);
     76         INPUT_TYPE_MAP.put(INPUT_TYPE_CEC_PLAYBACK, TvInputManagerHelper.TYPE_CEC_DEVICE_PLAYBACK);
     77         INPUT_TYPE_MAP.put(INPUT_TYPE_MHL_MOBILE, TvInputManagerHelper.TYPE_MHL_MOBILE);
     78         INPUT_TYPE_MAP.put(INPUT_TYPE_HDMI, TvInputInfo.TYPE_HDMI);
     79         INPUT_TYPE_MAP.put(INPUT_TYPE_DVI, TvInputInfo.TYPE_DVI);
     80         INPUT_TYPE_MAP.put(INPUT_TYPE_COMPONENT, TvInputInfo.TYPE_COMPONENT);
     81         INPUT_TYPE_MAP.put(INPUT_TYPE_SVIDEO, TvInputInfo.TYPE_SVIDEO);
     82         INPUT_TYPE_MAP.put(INPUT_TYPE_COMPOSITE, TvInputInfo.TYPE_COMPOSITE);
     83         INPUT_TYPE_MAP.put(INPUT_TYPE_DISPLAY_PORT, TvInputInfo.TYPE_DISPLAY_PORT);
     84         INPUT_TYPE_MAP.put(INPUT_TYPE_VGA, TvInputInfo.TYPE_VGA);
     85         INPUT_TYPE_MAP.put(INPUT_TYPE_SCART, TvInputInfo.TYPE_SCART);
     86         INPUT_TYPE_MAP.put(INPUT_TYPE_OTHER, TvInputInfo.TYPE_OTHER);
     87     }
     88 
     89     private Partner(String packageName, String receiverName, Resources res) {
     90         mPackageName = packageName;
     91         mReceiverName = receiverName;
     92         mResources = res;
     93     }
     94 
     95     /** Returns partner instance. */
     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. */
    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. */
    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. */
    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 
    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 
    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