ConsumerIrManage.hasIrEmitter() always returns fal

2019-01-21 15:40发布

问题:

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()?

回答1:

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.



回答2:

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?



回答3:

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.



回答4:

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.