Command Screen Implementation

This topic explains the implementation of the command screen.

The login screen is defined in the layout file fragment_command.xml. The elements in the XML file are associated with the class implementation as below.

As seen in Using Butter Knife, those are associated through annotations.

public class CommandFragment extends Fragment {
  @BindView(R.id.checkBoxPowerOn) CheckBox mCheckBoxPowerOn;
  @BindView(R.id.textViewBrightness) TextView mTextViewBrightness;
  @BindView(R.id.seekBarBrightness) SeekBar mSeekBarBrightness;
  @BindView(R.id.textViewCommandResult) TextView mCommandResult;
  @BindView(R.id.textViewStatePower) TextView mTextViewStatePower;
  @BindView(R.id.textViewStateBrightness) TextView mTextViewStateBrightness;
  @BindView(R.id.textViewMotion) TextView mTextViewStateMotion;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_command, container, false);
    mButterknifeUnbunder = ButterKnife.bind(this, view);
    ......
    return view;
  }

  @OnClick(R.id.buttonSend)
  void onSendCommand() {
    ......
  }

  @OnClick(R.id.buttonRefresh)
  void onRefreshState() {
    ......
  }
}

This topic explains the processes of sending commands with the SEND COMMAND button and getting state information with the REFRESH STATE button.

This topic does not discuss screen initialization with onCreateView() and the process that converts the slider position to a numeric value via OnSeekBarChangeListner when SeekBar is dragged. These are general processes in Android mobile apps.

Sending Commands

Once the command screen opens, clicking SEND COMMAND sends a command to the thing based on the parameters set on the screen.

See the below code for sending a command.

@OnClick(R.id.buttonSend)
void onSendCommand() {
  mCommandResult.setText("");

  List<Action> actions = new ArrayList<>();

  TurnPower action1 = new TurnPower();
  action1.power = mCheckBoxPowerOn.isChecked();
  actions.add(action1);

  if (action1.power) {
    SetBrightness action2 = new SetBrightness();
    action2.brightness = mSeekBarBrightness.getProgress();
    actions.add(action2);
  }

  PromiseAPIWrapper api = new PromiseAPIWrapper(mAdm, mApi);
  mAdm.when(api.postNewCommand(HelloThingIF.SCHEMA_NAME, HelloThingIF.SCHEMA_VERSION, actions)
  ).then(new DoneCallback<Command>() {
    @Override
    public void onDone(Command command) {
      String commandID = command.getCommandID();
      showToast("The command has been sent: " + commandID);
    }
  }).fail(new FailCallback<Throwable>() {
    @Override
    public void onFail(final Throwable tr) {
      showToast("Failed to send the command: " + tr.getLocalizedMessage());
    }
  });
}

First, the code clears the area for mCommandResult which displays the command result. It resets the display area before updating it with the command result of the command that you are going to send now.

Next, an array of actions which make up your command is prepared as actions. List<Action> is the type name because both TurnPower and SetBrightness are subclasses of Action.

The value of the Power ON check box is set in power in the TurnPower action. The brightness level of the slider is set in brightness in the SetBrightness action. The SetBrightness action is set only when the power is turned on.

The postNewCommand() method is called after necessary actions are set in actions.

  • If the command succeeds, the executed command will be passed to the onDone() method. This sample code displays the command ID in the toast for debugging.
  • If the command fails, the onFail() method will be called. It displays the error message in the toast.

The sample code defines one parameter for each action for power and brightness level. You can handle more complex commands according to the specification of the actual solution. You can define any commands as far as Java instances representing actions can be converted to JSON format.

See below for postNewCommand() implementation in PromiseAPIWrapper. postNewCommand() of ThingIFAPI is called from a worker thread with a promise.

public Promise<Command, Throwable, Void> postNewCommand(final String schemaName, final int schemaVersion, final List<Action> actions) {
  return mAdm.when(new DeferredAsyncTask<Void, Void, Command>() {
    @Override
    protected Command doInBackgroundSafe(Void... voids) throws Exception {
      return mApi.postNewCommand(schemaName, schemaVersion, actions);
    }
  });
}

Getting State Information

Clicking REFRESH STATE gets the latest state information from Thing Interaction Framework and updates the screen with it.

The above process is represented in the below code.

@OnClick(R.id.buttonRefresh)
void onRefreshState() {
  PromiseAPIWrapper api = new PromiseAPIWrapper(mAdm, mApi);
  mAdm.when(api.getTargetState()
  ).then(new DoneCallback<LEDState>() {
    @Override
    public void onDone(LEDState state) {
      if (getActivity() == null) {
        return;
      }
      if (state.power) {
        mTextViewStatePower.setText("Power: ON");
      } else {
        mTextViewStatePower.setText("Power: OFF");
      }
      mTextViewStateBrightness.setText("Brightness: " + state.brightness);
      mTextViewStateMotion.setText("Motion: " + state.motion);
      showToast("The state has been refreshed.");
    }
  }).fail(new FailCallback<Throwable>() {
    @Override
    public void onFail(final Throwable tr) {
      showToast("Failed to receive the state: " + tr.getLocalizedMessage());
    }
  });
}

When the button is clicked, the getTargetState() method of PromiseAPIWrapper is called. This method gets state information in a worker thread, and if the method succeeded, the obtained state information is stored in the LEDState class and the onDone() method is called.

State information can be obtained via LEDState specified in Onboarding. The value in each field is reflected on the screen and the toast which reads The state has been refreshed. is displayed.

See below for getTargetState() implementation in PromiseAPIWrapper. As with postNewCommand, getTargetState() of ThingIFAPI is called from a worker thread.

public Promise<LEDState, Throwable, Void> getTargetState() {
  return mAdm.when(new DeferredAsyncTask<Void, Void, LEDState>() {
    @Override
    protected LEDState doInBackgroundSafe(Void... voids) throws Exception {
      return mApi.getTargetState(LEDState.class);
    }
  });
}

What's Next?

Let us walk through the process of getting the command result. We will go over the implementation of push notification because push notification triggers the process of getting the command result.

Go to Getting the Command Result.

If you want to learn more...