Sample Code Analysis

 

This page analyzes each code of the sample application to show how to develop IR(infrared) remote control applications using the QRemote APIs.

For detailed description of each API, refer to LG QRemote API Reference.

 

The sample application consists of the following files:

 

Table 1. Files of the sample application

Files

Description

src/com/lge/qremotesdk/sample/SampleActivity.java

Main activity class

src/com/lge/qremotesdk/sample/LearnTestDialogFragment.java

Fragment for IR learning

res/layout/activity_main.xml

Main activity layout

res/layout/menu.xml

Context menus

 

In this page, only java source files are described. Detailed descriptions of the xml files will be found in Android Developer site.

Getting Ready

All codes described below can be found in SampleActivity.java.

Importing the IRBlaster Package

All classes using the LG QRemote APIs must import the IRBlaster package as follows:

 

import com.lge.hardware.IRBlaster.*;

Declaring Member Fields

public class SampleActivity extends Activity {
    private IRBlaster mIR;                    ①
    private Device[] mDevices;               ②
    boolean mIR_ready = false;               ③
    …
    private String[] mDeviceNames;          ④
    private String[] mFunctionNames;        ⑤
    private IRFunction mSelectedFunction;  ⑥
    private Device mDeviceSelected = null; ⑦
    …

    private Button buttonLearnSelectedDev; ⑧
    private Button buttonCreateDev;         ⑧
    …

    private ImageButton mPowerBtn;           ⑨
    private ImageButton mVolUpBtn;           ⑨
    private ImageButton mVolDownBtn;         ⑨
    private ArrayList<View> mBtnsArray = new ArrayList<View>();   ⑨

 

SampleActivity has member fields for UI components and control of IRBlaster. In the above codes, only the variables related with the IR Blaster are shown.

 

① an instance of IRBlaster

② list of the configured devices

③ flag indicating whether the IR Blaster is ready

④ name list of the configured devices

⑤ IR function list of the selected device

⑥ selected IR function

⑦ selected device

⑧ buttons for IR learning

⑨ buttons with assigned IR function labels and an ArrayList for these buttons

Setting Function Buttons

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    …
    mPowerBtn.setTag(IRFunctionLabels.IR_FUNCTION_LABEL_POWER_TV); ①
    mVolUpBtn.setTag(IRFunctionLabels.IR_FUNCTION_LABEL_VOLUME_UP_TV);
    mVolDownBtn.setTag(IRFunctionLabels.IR_FUNCTION_LABEL_VOLUME_DOWN_TV);

    mBtnsArray.add(mPowerBtn);                                             ②
    mBtnsArray.add(mVolUpBtn);
    mBtnsArray.add(mVolDownBtn);

    for (View v : mBtnsArray) {                                            ③
        v.setOnTouchListener(mIrButtonTouchListener);
    }
    …
}

 

① sets tags of the function buttons.

② adds buttons into an ArrayList.

③ sets listener to the buttons.

Getting an Instance of the IRBlaster Class

To use LG QRemote APIs, at least one instance of the IRBlaster class is needed. You can get the instance by getIRBlaster(). This method returns an instance of the IRBlaster class or null if there was an error.

 

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    …
    mHandler = new Handler();  
      
    mIR = IRBlaster.getIRBlaster(this, mIrBlasterReadyCallback); ①
    if (mIR == null) {              ②
        Log.e(TAG, "No IR Blaster in this device");
    }
}

 

In the above code, getIRBlaster() is called in the onCreate() method of SampleActivity. The instance of the IRBlaster class is created when the SampleActivity is created.

 

① gets an instance of the IRBlaster class. As a parameter to call getIRBlaster(), you should pass current context of the application and the instance of IRBlasterCallback interface.

② shows error messages when getting instance fails.

Implementing IRBlasterCallback

All codes described below can be found in SampleActivity.java.

 

To use IRBlaster, you need to implement IRBlasterCallback interface.

IRBlasterCallback is an interface which communicates with IR(infrared) services to control hardware. IRBlasterCallback interface has four callback methods: IRBlasterReady(), learnIRCompleted(), and newDeviceId(). You need to implement all of the method when you create anIRBlasterCallback interface.

 

These methods will be called whenever the actions of the IR Blaster hardware take place.

 

public IRBlasterCallback mIrBlasterReadyCallback = new IRBlasterCallback() {
    @Override
    public void IRBlasterReady() {                    ①
        Log.d(TAG, "IRBlaster is really ready");

        final Runnable r = new Runnable() {
            public void run() {
                getDevices();
            }
        };
        mHandler.post(r);
        mIR_ready = true;	
    }

    @Override
    public void learnIRCompleted(int status) {        ②
        Log.d(TAG, "Learn IR complete");

        if (learningDlgFragment != null) {
            LearnCompleteCallback callback =                
                          learningDlgFragment.getLearnCompleteCallback();
            if (callback != null) {
                callback.onComplete(status);
            }
        }
    }

    @Override
    public void newDeviceId(int id) {                   ③
        Log.d(TAG, "Added Device Id: " + id);
        Toast.makeText(SampleActivity.this,"New device id: " 
                                  + id, Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    public void failure(int error) {
        Log.e(TAG, "Error: " + ResultCode.getString(error));    ④
    }

 

① Implements IRBlasterReady().

IRBlasterReady() will be called just after the IR Blaster connects to hardware successfully.

Once the method is called, the flag mIR_ready will be set. it means that from now on you can use all methods provided by the IRBlaster class.

After initiating the IR Blaster hardware, the first action in the sample application is to get the list of configured device. It is recommended to call the methods from the IRBlaster class by creating new Runnable object and passing it as an argument to the handler. Implementation of thegetDevices() method is shown in Getting list of the configured devices.

 

② Implements learnIRCompleted().

learnIRCompleted() will be called when the learning process is completed and the result status is set. It is supported in the LG QRemote SDK revision 3 or above.

The sample application delegates the handling of the learning result to the learning window. If the learning process is complete, the sample application calls onComplete() for the learning window to handle the result.

 

③ Implements newDeviceId().

newDeviceId() will be called when a new device is configured and added. Configuring devices is done by LG QRemote. After configuring, a detected device will be added to the device list for the sample application. You do not have to implement the code to add devices manually.

 

④ Implements failure().

failure() will be called when the process of IR services fails. Sample application displays the cause of failure.

 

Getting List of the Configured Devices

All codes described below can be found in SampleActivity.java.

 

Once IRBlasterReady() is invoked you can get the list of devices by calling the getDevices() method of SampleActivity.

All methods called from the IRBlaster class should be surrounded by try-catch statement because it can throw RemoteException.

 

public void getDevices() {
    try {
        mDevices = mIR.getDevices();                    ①
        if (mDevices == null || mDevices.length == 0) {
            mDeviceSelected = null;
            mSelectedFunction = null;
            mDeviceNames = new String[1];
            mDeviceNames[0] = "";
            mFunctionNames = new String[1];
            mFunctionNames[0] = "";
            return;
        }
        mDeviceNames = new String[mDevices.length];
        int i = 0; 
        for (Device d : mDevices) {                    ②
            mDeviceNames[i++] = d.Name;
            Log.d(TAG, d.Name);
        }
        If (mDevices.length > 0) {                     ③                
            mDeviceSelected = mDevices[0];
 
                List<IRFunction> functions = mDeviceSelected.KeyFunctions;
                if ((functions != null) &&
                        !functions.isEmpty()) {
                    mSelectedFunction = functions.get(0);
                    mFunctionNames = new String[functions.size()];
                    int j = 0;
                    for (IRFunction fun : functions) {
                        mFunctionNames[j++] = fun.Name;
                    }
        …
    } catch (RemoteException e) {        
        Log.e(TAG, "IRBlaster is not responding.");
        e.printStackTrace();
    } finally {                                           ④
        attachSpinner();
        attachSpinnerFun();
    }
}

 

① gets the list of devices by IRBlaster.getDevices(). IRBlaster.getDevices() returns an array of instances of the Device class or null if there was an error. If an error occurred or there is no configured device, SampleActivity will do nothing.

② retrieves the names of devices.

③ retrieves the IR function list of the selected device. SampleActivity assumes that the first device is selected by user, acquires the IR function list from the selected device through the KeyFunctions, a member field of the Device class.

④ refreshes the device list and the IR function list on the screen. attachSpinner() and attachSpinnerFun() will not be described in this document.

 

Sending IR Signals

All codes described below can be found in SampleActivity.java.

Using IR Functions

SampleActivity has the ‘test’ button to test the selected IR function of the device.

An OnTouchListener interface needs to be implemented to handle user's touch on the button.

The following codes are parts of declaration of OnTouchListener. The omitted codes can be found in SampleActivity.java.

 

private OnTouchListener mButtonAddOnTouchListener = new OnTouchListener() { 
    @Override
    public boolean onTouch(View v, MotionEvent event) {    
        int id = v.getId();
        if (id == R.id.buttonTest) {                        ①
            int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN) {     ②
                final Runnable r = new Runnable() {
                    public void run() {
                        String result;
                        if (mDeviceSelected != null) {
                            result = mDeviceSelected.Name + " -->" +                
                                       mSelectedFunction.Name + " ->" + 
                                       ResultCode.getString(
                                          mIR.sendIR(new IRAction(
                         mDeviceSelected.Id, mSelectedFunction.Id,0))) + "\n";
                        } else {
                            result = "No devices" + "\n";
                        }
                        mTextView.append(result);
                    }
                 };
                 mHandler.post(r);
             } else if (action == MotionEvent.ACTION_OUTSIDE    ③
                       || action == MotionEvent.ACTION_CANCEL
                       || action == MotionEvent.ACTION_UP) {
                 if (mDeviceSelected != null) {
                     mIR.stopIR();
                 }
            }
        }
    }
    …
};

 

① implements the onTouch() method for the ‘test’ button. In the sample application, the IR(infrared) signals will be sent continuously while users are pressing it. The signals will be stopped when users take their fingers off the button.

② handles the touch-down event of the button. On receiving MotionEvent.ACTION_DOWN events, the sendIR() method which sends IR signals will be called. Note that sendIR() will be executed in a new thread.

sendIR() method takes an object of the IRAction class as a parameter.

IRAction class describes the action that you want to perform: ID of the device that you want to send IR command to, ID of the IR function you intend to send, and the last parameter is the duration of the command in milliseconds. When the duration is set to 0, commands will be sent continuously. You can get the default duration of the IR command by calling the method getDefaultDuration(). It will return default duration in milliseconds.

③ handles the touch-released event of the button. On receiving a MotionEvent.ACTION_UP, MotionEvent.ACTION_OUTSIDE orMotionEvent.ACTION_CANCEL events, sending IR signals is stopped by calling stopIR().

Using raw IR Data

SampleActivity has a button to test the sending of raw IR data. The button sends IR signals to power on or off LG TVs using raw IR data.

 

private void sendLgTvPower() {
    // test sendIRPattern() 
    int[] LGTVPower ={ 9000, 4500, 578, 552, 578, 552, 578, 1684, 578, 552,
                578, 552, 578, 552, 578, 552, 578, 552, 578, 1684,
                578, 1684, 578, 552, 578, 1684, 578, 1684, 578, 1684,
                578, 1684, 578, 1684, 578, 552, 578, 552, 578, 552,
                578, 1684, 578, 552, 578, 552, 578, 552, 578, 552,
                578, 1684, 578, 1684, 578, 1684, 578, 552, 578, 1684,
                578, 1684, 578, 1684, 578, 1684, 578, 39342, 9000, 2236,
                578, 96184, 9000, 2236, 578, 96184 };             ①
     mIR.sendIRPattern(38000, LGTVPower);                         ②
}

 

① defines the timing patterns of the IR signals to send. These patterns should already be known to developers. See Developing for details.

② sends IR signals with frequency and raw IR data (timing patterns).

Learning IR Data

All of the codes described below can be found in LearnTestDialogFragment.java.

Creating a new Device

LearnTestDialogFragment receives the selected device from SampleActivity when it starts. If the selected device is null (That means the user clicks the ‘create device’ button in SampleActivity), it creates a new device to store the learned IR data.

 

private void initFuncList() {
    if (mDev != null) {                 
         Log.i(TAG, "Get functions from an existing device with ID [" + mDev.Id + "].");
         updateListView();
    } else {
            Log.i(TAG, "Create a new device.");
            mDev = mIr.createDevice(   ①
                          "learn device", "learn test", "learn test");
        }
    }

 

① creates a device with the custom type(e.g. “learn device”), brand(e.g. “learn test”) and name(e.g. “learn test”).

Starting a Learning Process

public void handleMessage(Message msg) {
    switch (msg.what) {
         case START_IR_LEARNING:
              // start learning process
              mIr.startIrLearning();    ①

              int result = mIr.getLastResultcode();

              if (result == ResultCode.SUCCESS) {
                   Log.d(TAG, "Learning process is started. Waiting for the callback…");
              }
              // Show a progress dialog
              if (mHandler != null) {  ②
                    mHandler.removeMessages(SHOW_LEARNING_ANI);
                    mHandler.sendMessageDelayed(
                              mHandler.obtainMessage(SHOW_LEARNING_ANI),
                              EFFECT_DELAY);
              }
              …
    }
}

 

① starts a learning process. When this method is called, IR services wait for the IR signals from the external remote. It will take 30 seconds maximum.

② shows a progress dialog during the learning process.

Handling the Result

As seen at Implementing IRBlasterCallback, learnedIRCompleted() is called when the learning is complete. The learnedIRCompleted() method calls onComplete() for the learning window to handle the result.

 

@Override
public void onComplete(int status) {
    ...
            
    // handle result status
    if (status == ResultCode.SUCCESS) {         ①
         mLearnedIrData = mIr.getLearnedData(); ②
         if (mLearnedIrData == null) {
              Log.e(TAG, "Learned data is NULL.");
         }
         // Add or edit the learned function into the SDK.
         if (mLearningFuncId != -1) {
              // Edit the existing function.
             mIr.editIrFunctionWithLearnedData(mDev.Id, mLearningFuncId); ③
         } else {
              // Save new function.
              mLearningFuncId = mIr.addLearnedIrFunction(
                                          mDev.Id, mLearningFuncName); ④
              ...
              updateDevice();                      ⑤
                
              ...
        } else {                                     ⑥
             if (status == ResultCode.IRLEARNING_ABORTED) {
                    // Learning is cancelled by a user.
                    // Do nothing.
             } else {
                    if (status == ResultCode.IRLEARNING_TIMEOUT) {
                        // show a timeout message
                        ...
                    } else if (status == ResultCode.IRLEARNING_FAILED) {
                        // show a failure message
                        ...
                    }
                }
            }
        }
    };

 

① checks if learning IR data is successful.

② retrieves the last learned IR data. It is stored for future use.

③ stores the learned IR data into an existing IR function in the device.

④ stores the learned IR data as a new IR function in the device.

⑤ refreshes the IR function list of the device.

 

checks if the learning process has failed. If yes, the status shows the cause of the failure. In these cases, the sample application shows the failure cause.

Sending Learned IR Data

SampleActivity implements a button that requests to send IR signals for learned IR data when pressed.

Button learnedIrBtn = (Button)findViewById(R.id.learned_ir_btn);   ①
learnedIrBtn.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        if( learningDlgFragment != null ) {
            LearnedIr learnedIrData =
                                  learningDlgFragment.getLastLearnedData();②
        if( learnedIr != null ) {
            int result = mIR.sendIrWithLearnedData(learnedIr.Data, ③
                                                learnedIr.Id, 200, false);
            Log.d("test", "result = "
                                    + ResultCode.getString(result)); 
        }
        else 
            Log.d("test", "no learned data");
        }
    }
});

 

① Gets a button for sending learned IR data.

② Retrieves the learned IR data stored in LearningDigFragment.

③ Sends IR signals when there is any IR data learned.

Getting Function Keycode

All codes described below can be found in SampleActivity.java.

 

SampleActivity has two graphical buttons: power button and volume up/down button.

Once users select a device in the list, SampleActivity should check whether the selected device supports those IR functions. If the IR functions don’t exist in the device, it makes the buttons disabled.

 

for (final View v : mBtnsArray) {
    String label = (String)v.getTag();
    int keyCode = getFunctionKeyCode(label); ①
    …
    if (keyCode == -1) {
         runOnUiThread(new Runnable() {
              @Override
              public void run() {
                   v.setEnabled(false);          ②
              }
        });

        Log.d(TAG, "check [" + label + "] result disabled");
    } else {
        runOnUiThread(new Runnable() {
             @Override
             public void run() {
                  v.setEnabled(true);            ③
             }
        });

        Log.d(TAG, "check [" + label + "] result enabled");
    }
}

 

① gets IR function ID by label. The argument label is an IR function label defined in IRFunctionLabels.

② disables function buttons, if the selected device does NOT support the IR function.

③ enables function buttons, if the selected device support the IR function.

Adding and Deleting Device

All codes described below can be found in SampleActivity.java.

 

Adding and deleting devices are supported by the sample application through the context menu, which appears when you press the menu button of the phone.

As mentioned in Introduction, to add a device, you need to configure the device on LG QRemote. After the configuration is finished, SampleActivity will be shown again.

 

Devices that you add through the LG QRemote APIs will not be seen in LG QRemote. Although 3rd party applications can see all devices which added in the LG QRemote database, user can only delete devices added through the LG QRemote APIs.

 

You should implement an onOptionsItemSelected() callback to handle the context menu.

 

public boolean onOptionsItemSelected(MenuItem item) {
    int itemId = item.getItemId();
    if (itemId == R.id.add_device) {                       ①
        if (mIR_ready == true && mIR != null) {
            int result = mIR.addDevice();
            …
        }
        return true;
    } else if (itemId == R.id.delete_device) {           ②
        if (mIR_ready == true && mIR != null) {
            if (mDevices == null || mDevices.length == 0) 
                return false;
            int result = mIR.deleteDevice(mDeviceSelected.Id);
            …
            getDevices();
        }
        return true;
    } else {
        return super.onOptionsItemSelected(item);
    }
}

 

① Implements the ‘Add device’ menu by calling the IRBlaster.addDevice() method. This method will call LG QRemote to configure devices.

② Implements the ‘Delete device’ menu by calling the IRBlaster.deleteDevice() method. You must pass ID of the device to theIRBlaster.deleteDevice() method. The ID can be retrieved from the Device object.

 

Navigation