6

I call ConsumerIrManager.hasIrEmitter() on my LG G2, but it always returns false.

According to the documentation on Infrared transmitters:

When running on a device that includes an infrared (IR) transmitter, you can now transmit IR signals using the ConsumerIrManager APIs. To get an instance of ConsumerIrManager, call getSystemService() with CONSUMER_IR_SERVICE as the argument. You can then query the device's supported IR frequencies with getCarrierFrequencies() and transmit signals by passing your desired frequency and signal pattern with transmit().

You should always first check whether a device includes an IR transmitter by calling hasIrEmitter(), but if your app is compatible only with devices that do have one, you should include a <uses-feature> element in your manifest for "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

My code is as follows:

MainActivity.java

import android.hardware.ConsumerIrManager;
....

@Override
protected void onCreate(Bundle savedInstanceState) {
    ....
    ConsumerIrManager mCIR = (ConsumerIrManager)getSystemService(CONSUMER_IR_SERVICE);
    Log.e(TAG, "mCIR.hasIrEmitter(): " + mCIR.hasIrEmitter());
    PackageManager pm = getPackageManager();
    Log.e(TAG, "pm.hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR): "
        + pm.hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR));
    FeatureInfo[] fi = pm.getSystemAvailableFeatures();
    for (int i = 0; i < fi.length; i++) {
        Log.e(TAG, "Feature: " + fi[i].name);
    }
    ....
}

AndroidManifest.xml

<uses-permission android:name="android.permission.TRANSMIT_IR" android:required="false" />
<uses-feature android:name="android.hardware.consumerir" />

In SystemAvailableFeatures list I cannot see "android.hardware.consumerir" (FEATURE_CONSUMER_IR), but the LG G2 definitely has IR.

Has anyone successfully used hasEmitterIr()?

Ray
  • 7,940
  • 7
  • 58
  • 90
kallianas
  • 121
  • 1
  • 1
  • 6

4 Answers4

15

For anyone else who wants to go from a hex IR code to a decimal 'count' pattern to a decimal 'duration' pattern:

Samsung Power hex code (From remotecentral.com):

0000 006d 0022 0003 00a9 00a8 0015 003f 0015 003f 0015 003f 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 003f 0015 003f 0015 003f 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 003f 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0015 0040 0015 0015 0015 003f 0015 003f 0015 003f 0015 003f 0015 003f 0015 003f 0015 0702 00a9 00a8 0015 0015 0015 0e6e

Convert to decimal using the hex2dec method in irdude:

38028,169,168,21,63,21,63,21,63,21,21,21,21,21,21,21,21,21,21,21,63,21,63,21,63,21,21,21,21,21,21,21,21,21,21,21,21,21,63,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,63,21,63,21,63,21,63,21,63,21,63,21,1794,169,168,21,21,21,3694

Use the first argument as your frequency and put the rest in an int array for your Count Pattern:

private static final int SAMSUNG_FREQ = 38028;
private static final int[] SAMSUNG_POWER_TOGGLE_COUNT = {169,168,21,63,21,63,21,63,21,21,21,21,21,21,21,21,21,21,21,63,21,63,21,63,21,21,21,21,21,21,21,21,21,21,21,21,21,63,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,63,21,63,21,63,21,63,21,63,21,63,21,1794,169,168,21,21,21,3694};

Use the frequency to find the pulses per second:

Frequency: 38028; 
Second: 1,000,000 Microseconds
Second/Frequency = Pulses
1000000/38028 = ~26.3 Pulses

Convert the Count Pattern to Duration Pattern by multiplying each value by the pulses:

169 * 26.3 = 4444
168 * 26.3 = 4418
21 * 26.3 = 552
...

If you want a quick way to get a string with all of the Duration values, then just run your hex code through the hex2dec method and then use that output in this method:

protected String count2duration(String countPattern) {
    List<String> list = new ArrayList<String>(Arrays.asList(countPattern.split(",")));
          int frequency = Integer.parseInt(list.get(0));
          int pulses = 1000000/frequency;
          int count;
          int duration;

          list.remove(0);

          for (int i = 0; i < list.size(); i++) {
           count = Integer.parseInt(list.get(i));
           duration = count * pulses;
           list.set(i, Integer.toString(duration));
          }

          String durationPattern = "";
          for (String s : list) {
           durationPattern += s + ",";
          }

          Log.d(TAG, "Frequency: " + frequency);
          Log.d(TAG, "Duration Pattern: " + durationPattern);

    return durationPattern;
}

That will print the string of decimal duration values to the log. I would then just copy that (not including the first value) and make a static final int array like this:

    private static final int[] SAMSUNG_POWER_TOGGLE_DURATION = {4495,4368,546,1638,546,1638,546,1638,546,546,546,546,546,546,546,546,546,546,546,1638,546,1638,546,1638,546,546,546,546,546,546,546,546,546,546,546,546,546,1638,546,546,546,546,546,546,546,546,546,546,546,546,546,1664,546,546,546,1638,546,1638,546,1638,546,1638,546,1638,546,1638,546,46644,4394,4368,546,546,546,96044};

So now that you have your two patterns as static final int arrays, you can transmit:

ConsumerIrManager mCIR;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Get a reference to the ConsumerIrManager
    mCIR = (ConsumerIrManager) this.getSystemService(Context.CONSUMER_IR_SERVICE);

    setContentView(R.layout.consumer_ir);

    // Set the OnClickListener for the button so we see when it's pressed.
    findViewById(R.id.send_button).setOnClickListener(mSendClickListener);
}


View.OnClickListener mSendClickListener = new View.OnClickListener() {
    public void onClick(View v) {
        if (!mCIR.hasIrEmitter()) {
            Log.e(TAG, "No IR Emitter found\n");
            return;
        }

        if (Build.VERSION.SDK_INT == 19) {
            int lastIdx = Build.VERSION.RELEASE.lastIndexOf(".");
            int VERSION_MR = Integer.valueOf(Build.VERSION.RELEASE.substring(lastIdx+1));
            if (VERSION_MR < 3) { 
             // Before version of Android 4.4.2
            mCIR.transmit(SAMSUNG_FREQ, SAMSUNG_POWER_TOGGLE_COUNT);
            } else { 
             // Later version of Android 4.4.3
             mCIR.transmit(SAMSUNG_FREQ, SAMSUNG_POWER_TOGGLE_DURATION);
            }
        }
    }   
};

Note: I'm not sure which pattern 4.4.4 needs.

Randy
  • 955
  • 9
  • 16
  • This worked for me but only for a Samsung. DO you think you can work it for HTC? – joyBlanks Aug 23 '15 at 16:13
  • This was for an HTC phone I believe. What version of Android are you on? – Randy Aug 24 '15 at 00:35
  • I am on Android 5.0 HTC m8. Yup I had written the code for htc earlier before API change and used to work on HTC but not on Samsung now its reverse, cant get it to work on HTC – joyBlanks Aug 24 '15 at 00:37
  • 1
    I spotted a missing value on the second array (SAMSUNG_POWER_TOGGLE_DURATION). It seems that value of 169 was not converted. If this is the array you'll be using add `4495` before 4368. The code wasn't working until I figured out the array lengths weren't matching. Now it works. – 0014 Oct 02 '16 at 05:15
  • @0014, thanks... Edited the answer to add the missing value. – Randy Oct 02 '16 at 18:05
3

I tried ConsumerIrManager using HTC One Google Play Edition.

consumerIrManager.hasIrEmitter() returned true. And I could transmit IR codes by consumerIrManager.transmit().

But I had a problem that the behavior of transmit() was different from the Android API document.

The API document is as follows.

public void transmit (int carrierFrequency, int[] pattern)
  Tansmit and infrared pattern 
  This method is synchronous; when it returns the pattern has been transmitted. 
  Only patterns shorter than 2 seconds will be transmitted.

  Parameters
    carrierFrequency    The IR carrier frequency in Hertz.
    pattern                 The alternating on/off pattern in microseconds to transmit.

But it seemed that the unit of parameter "pattern" was 25microseconds, not microseconds. This is because the length of one pulse of the carrier was 25microseconds. (I set carrierFrequency to 40000Hz, so the length of one pulse was 25microseconds.)

I am not sure whether this a porting bug of HTC One Google Play Edition, or a bug of Android 4.4.


Note: Just something I noticed while trying to use the IR on a Samsung Tab2 was the timing periods were also off by a factor of 25.6 (actual pulse length / 25.6) so could this be a internal function of the IR transmitter module?

Community
  • 1
  • 1
kita yuki
  • 31
  • 2
  • This is also the case for Samsung Galaxy Note 3. It seems like the API documentation is incorrect... – pqvst Apr 24 '14 at 09:36
  • Damn Android documentation. I have wasted the whole yesterday evening wondering why my code did not work. After reading this, I just divided the length by 25.6 and it worked. Android documentation clearly says "The alternating on/off pattern in microseconds to transmit". – Damn Vegetables Jun 10 '14 at 14:17
  • I am using Poco X3 NFC, Android 12. The API is correct. The pattens are actually in microseconds. No need to scale to 25 microseconds. – eos1d3 Apr 20 '23 at 09:47
1

I have this working fine on HTC One using CM 11. The pattern array contains the number of pulse, not the timings. This is an error in Google documentation.

I suspect it won't work on LG and Sony as they use an IR chip with built in databse of codes. I hope I'm wrong about this.

Touchsquid apps will have this driver shortly.

TStech
  • 11
  • 1
  • Do you know how to convert a Pronto Hex Code to a correct ConsumerIr pattern (int[])?? I am using a variant if the hex2dec method from here: https://github.com/rngtng/IrDude/blob/master/src/com/rngtng/irdude/MainActivity.java but instead of returning a string i return an int[] table with the dec values. It seems that is not working.. Something wrong with the conversion?? – kallianas Apr 08 '14 at 14:52
  • OK, i figure out my mistake. The problem was that the frequency was added at the beginning of the table and is not needed as you provide it as the first parameter on ConsumerIrManager.transmit(int carrierFrequency, int[] pattern)!! – kallianas Apr 09 '14 at 11:38
0

I made a small app to test IR Balster on my LG G2 using

https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/hardware/ConsumerIr.java

https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/res/layout/consumer_ir.xml

It gave me a message: "No IR Emitter found!"

The function hasIrEmitter() returns false. The ConsumerIrManager API does not seems to be implemented.

XcinnaY
  • 274
  • 2
  • 10
  • Same on Sony Xperia ZL. I do not understand why ConsumerIrManager doesn´t work on all KitKat Devices with Infrared Transmitter. I thought this is why ConsumerIrManager was integrated to KitKat. Note: On LG G2 you can use the QRemoteSDK from LG. –  Aug 25 '14 at 15:17