{"content":"2740→        View anchor = findViewById(underGear ? R.id.btnSettings : R.id.btnInputs);\n2741→        View panel = getLayoutInflater().inflate(R.layout.popup_inputs, root, false);\n2742→        LinearLayout rows = panel.findViewById(R.id.rows);\n2743→\n2744→        // Compact: as wide as the Inputs pill (a touch wider so \"HDMI 1\" fits), hanging right below it.\n2745→        int width = Math.max(anchor.getWidth(), (int) (150 * density));\n2746→        final PopupWindow popup = glassPopup(panel, width);\n2747→\n2748→        TvInputManager tim = (TvInputManager) getSystemService(TV_INPUT_SERVICE);\n2749→        boolean sawNonHdmi = false;\n2750→        String tunerId = null;\n2751→        boolean tunerIsHw = false;\n2752→        boolean tunerIsAnalog = false;\n2753→        if (tim != null) {\n2754→            List<TvInputInfo> inputs = new ArrayList<>(tim.getTvInputList());\n2755→            // HDMI ports first in port order, then AV and the rest.\n2756→            Collections.sort(inputs, (a, b) -> {\n2757→                boolean ha = a.getType() == TvInputInfo.TYPE_HDMI, hb = b.getType() == TvInputInfo.TYPE_HDMI;\n2758→                if (ha != hb) return ha ? -1 : 1;\n2759→                return String.valueOf(a.loadLabel(this)).compareToIgnoreCase(String.valueOf(b.loadLabel(this)));\n2760→            });\n2761→            // An HDMI-CEC device (an Apple TV, a soundbar) gets an input of its own whose parent is the\n2762→            // port it sits on, so the port and the device would each get a row (Vestel MT7332: \"HDMI 1\"\n2763→            // and \"HDMI Apple TV\"). The device takes its port's row instead, and a bare port is listed\n2764→            // only when nothing on it speaks CEC.\n2765→            Set<String> inputIds = new HashSet<>();\n2766→            for (TvInputInfo info : inputs) inputIds.add(info.getId());\n2767→            Map<String, List<TvInputInfo>> cecDevices = new HashMap<>();\n2768→            for (TvInputInfo info : inputs) {\n2769→                String parent = info.getParentId();\n2770→                if (parent == null || !inputIds.contains(parent)) continue;\n2771→                if (!info.isPassthroughInput() || inputHidden(info)) continue;\n2772→                List<TvInputInfo> onPort = cecDevices.get(parent);\n2773→                if (onPort == null) cecDevices.put(parent, onPort = new ArrayList<>());\n2774→                onPort.add(info);\n2775→            }\n2776→            // Some TVs (Sony) report every HDMI port as connected whether or not anything is plugged in,\n2777→            // so drop the HDMI status then. A TV with every port really in use loses it too.\n2778→            int hdmiPorts = 0, hdmiConnected = 0;\n2779→            for (TvInputInfo info : inputs) {\n2780→                if (!info.isPassthroughInput() || info.getType() != TvInputInfo.TYPE_HDMI) continue;\n2781→                if (info.getParentId() != null && inputIds.contains(info.getParentId())) continue;\n2782→                hdmiPorts++;\n2783→                if (tim.getInputState(info.getId()) == TvInputManager.INPUT_STATE_CONNECTED) hdmiConnected++;\n2784→            }\n2785→            boolean hdmiStateBogus = hdmiPorts > 1 && hdmiConnected == hdmiPorts;\n2786→            for (TvInputInfo info : inputs) {\n2787→                if (info.getType() == TvInputInfo.TYPE_TUNER\n2788→                        && (info.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0\n2789→                        && (liveTvInputId.isEmpty() || liveTvInputId.equals(info.getId()))) {\n2790→                    // Prefer a hardware tuner: the framework names those \".../HW<n>\". System apps such as\n2791→                    // AirPlay also register software inputs of type TUNER and may sort first (seen on TCL G05).\n2792→                    // Among tuners of the same kind, skip an analog input when another is present.\n2793→                    // MediaTek names them AnalogInputService and TunerInputService; alphabetical order\n2794→                    // would pick the analog one, and Live TV then opens a dead ATV source.\n2795→                    boolean hw = info.getId().matches(\".*/HW\\\\d+$\");\n2796→                    boolean analog = info.getId().toLowerCase(Locale.ROOT).contains(\"analog\");\n2797→                    boolean better = tunerId == null\n2798→                            || (hw && !tunerIsHw)\n2799→                            || (hw == tunerIsHw && tunerIsAnalog && !analog)\n2800→                            || (hw == tunerIsHw && analog == tunerIsAnalog\n2801→                                    && info.getId().compareTo(tunerId) < 0);\n2802→                    if (better) {\n2803→                        tunerId = info.getId();\n2804→                        tunerIsHw = hw;\n2805→                        tunerIsAnalog = analog;\n2806→                    }\n2807→                }\n2808→                // Inputs hidden in the TV's Settings > Inputs stay out of the menu too.\n2809→                if (!info.isPassthroughInput() || inputHidden(info)) continue;\n2810→                // input_sources can leave out ports the board reports but the set does not have (\"HW8=-\").\n2811→                if (Integer.valueOf(-1).equals(mappedSource(info.getId()))) continue;\n2812→                // A CEC device's row is added with its port, below.\n2813→                if (info.getParentId() != null && inputIds.contains(info.getParentId())) continue;\n2814→                CharSequence l = info.loadLabel(this);\n2815→                String label = l == null ? info.getId() : l.toString();\n2816→                boolean hdmi = info.getType() == TvInputInfo.TYPE_HDMI;\n2817→                if (hdmi && !label.toUpperCase(Locale.ROOT).contains(\"HDMI\")) label = \"HDMI \" + label;\n2818→                CharSequence custom = inputCustomLabel(info);\n2819→                boolean named = custom != null && custom.length() > 0 && !custom.toString().equals(label);\n2820→                if (!hdmi && rows.getChildCount() > 0 && !sawNonHdmi) addSeparator(rows);\n2821→                if (!hdmi) sawNonHdmi = true;\n2822→                List<TvInputInfo> devices = cecDevices.get(info.getId());\n2823→                if (devices != null) {\n2824→                    // \"Apple TV · HDMI 1\": the device's own name (or the one given to it or to its port in\n2825→                    // Settings > Inputs), then the port. Opening the device's input also makes it the CEC\n2826→                    // active source, which wakes it.\n2827→                    for (TvInputInfo device : devices) {\n2828→                        CharSequence name = inputCustomLabel(device);\n2829→                        if (name == null || name.length() == 0) name = named ? custom : device.loadLabel(this);\n2830→                        String deviceLabel = name == null || name.length() == 0 ? label : name + \" \\u00B7 \" + label;\n2831→                        final String deviceId = device.getId();\n2832→                        int state = hdmiStateBogus ? -1 : tim.getInputState(deviceId);\n2833→                        addInputRow(rows, popup, R.drawable.ic_input, deviceLabel, state, () -> openInput(deviceId));\n2834→                    }\n2835→                    continue;\n2836→                }\n2837→                // The name given in Settings > Inputs (e.g. \"MacBook Pro\") goes first, the port after it.\n2838→                if (named) label = custom + \" \\u00B7 \" + label;\n2839→                final String id = info.getId();\n2840→                // Analog AV jacks have no hotplug detection, and some TVs report them as always connected\n2841→                // (TCL Smart TV Pro G03 says \"Connected\" with nothing plugged in), so AV rows show no state.\n2842→                int state = !hdmi || hdmiStateBogus ? -1 : tim.getInputState(id);\n2843→                addInputRow(rows, popup, hdmi ? R.drawable.ic_input : R.drawable.ic_av, label, state,\n2844→                        () -> openInput(id));\n2845→            }\n2846→            // Local fork for MiTV4-ANSM0: this firmware never registers the HDMI port that actually has a\n2847→            // device on it (HDMI1/HW5 with the IPTV box), while ports with nothing plugged in do get\n2848→            // registered. List every input_sources entry whose framework input is missing, so the port is\n2849→            // still one click away. Needs input_action, which is how a mapped input opens anyway.\n2850→            if (!inputAction.isEmpty()) {\n2851→                for (String m : getResources().getStringArray(R.array.input_sources)) {\n2852→                    int eq = m.indexOf('=');\n2853→                    if (eq <= 0) continue;\n2854→                    String hw = m.substring(0, eq).trim();\n2855→                    if (!hw.matches(\"HW\\\\d+\")) continue;\n2856→                    boolean registered = false;\n2857→                    for (TvInputInfo info : inputs) {\n2858→                        if (info.getId().endsWith(\"/\" + hw)) { registered = true; break; }\n2859→                    }\n2860→                    if (registered) continue;\n2861→                    String rest = m.substring(eq + 1).trim();\n2862→                    int colon = rest.indexOf(':');\n2863→                    String name = colon >= 0 ? rest.substring(colon + 1).trim() : \"\";\n2864→                    int source;\n2865→                    try { source = Integer.parseInt(colon >= 0 ? rest.substring(0, colon).trim() : rest); }\n2866→                    catch (NumberFormatException e) { continue; }\n2867→                    if (source < 0) continue;\n2868→                    final String syntheticId = \"unregistered/\" + hw;\n2869→                    addInputRow(rows, popup, R.drawable.ic_input,\n2870→                            name.isEmpty() ? hw : name, -1, () -> openInput(syntheticId));\n2871→                }\n2872→            }\n2873→        }\n2874→        // Coocaa OS registers nothing with TvInputManager; com.skyworth.tv lists its sources instead.\n2875→        if (rows.getChildCount() == 0) {\n2876→            for (CoocaaSources.Source s : coocaa) {\n2877→                int icon = \"HDMI\".equals(s.name) ? R.drawable.ic_input\n2878→                        : \"VOD\".equals(s.name) ? R.drawable.ic_livetv : R.drawable.ic_av;\n2879→                addInputRow(rows, popup, icon, s.label, -1, () -> {\n2880→                    if (!CoocaaSources.open(this, s)) {\n2881→                        Toast.makeText(this, R.string.not_available, Toast.LENGTH_SHORT).show();\n2882→                    }\n2883→                });\n2884→            }\n2885→        }\n2886→        // Nothing to list where there is no TvInputManager: the TV's own source panel switches inputs.\n2887→        if (rows.getChildCount() == 0 && !sourcePanelService.isEmpty()) {\n2888→            addInputRow(rows, popup, R.drawable.ic_input, getString(R.string.inputs), -1, this::openSourcePanel);\n2889→        }\n2890→        Intent liveTv = liveTvIntent();\n2891→        if (liveTv != null && tunerId != null) {\n2892→            // Tune that input only when the Live TV package itself handles the URI.\n2893→            // The unrestricted input player also resolves it (that is how HDMI opens), but on the\n2894→            // AIWA AI PONT SA that player stays black, and the Live TV package does not handle the\n2895→            // URI at all, which used to toast \"Not available on this TV\". Keep the leanback activity\n2896→            // then: it is the same path as the Live TV tile. Do not drop the package restriction.\n2897→            // An explicit tuner uses its channel collection (e.g. DVB-S rather than DVB-T/C).\n2898→            // Keep the legacy passthrough route for automatic selection: some OEM players need it.\n2899→            // If the configured input is absent, tunerId stays null and the app opens normally.\n2900→            boolean configured = !liveTvInputId.isEmpty();\n2901→            Intent tuned = new Intent(Intent.ACTION_VIEW)\n2902→                    .setDataAndType(configured ? TvContract.buildChannelsUriForInput(tunerId)\n2903→                                    : TvContract.buildChannelUriForPassthroughInput(tunerId),\n2904→                            configured ? TvContract.Channels.CONTENT_TYPE : TvContract.Channels.CONTENT_ITEM_TYPE)\n2905→                    .setPackage(liveTvPkg);\n2906→            if (tuned.resolveActivity(getPackageManager()) != null) liveTv = tuned;\n2907→        }\n2908→        if (liveTv != null) {\n2909→            if (rows.getChildCount() > 0) addSeparator(rows);\n2910→            final Intent liveTvIntent = liveTv;\n2911→            addInputRow(rows, popup, R.drawable.ic_livetv, getString(R.string.live_tv), -1, () -> open(liveTvIntent));\n2912→        }\n2913→        if (rows.getChildCount() == 0) {\n2914→            Toast.makeText(this, R.string.no_inputs, Toast.LENGTH_SHORT).show();\n2915→            return;\n2916→        }\n2917→\n2918→        // Fit the widest row: TVs that report a status on every port (Sony) would otherwise squeeze the names out.\n2919→        panel.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);\n2920→","renderer":{"type":"code","context":{"language":"java"}}}